diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..984ca24 --- /dev/null +++ b/.classpath @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..712cd0d --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + hFactions + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a21537 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/src/compat/com/google/common/collect/FluentIterableCompat.java b/src/compat/com/google/common/collect/FluentIterableCompat.java new file mode 100644 index 0000000..cb63706 --- /dev/null +++ b/src/compat/com/google/common/collect/FluentIterableCompat.java @@ -0,0 +1,48 @@ +package compat.com.google.common.collect; + +import com.google.common.annotations.*; +import java.util.*; +import javax.annotation.*; +import com.google.common.base.*; +import com.google.common.collect.*; + +@GwtCompatible(emulated = true) +public abstract class FluentIterableCompat implements Iterable { + private final Iterable iterable; + + @SuppressWarnings("unchecked") + FluentIterableCompat(final Iterable iterable) { + this.iterable = (Iterable) Preconditions.checkNotNull((Object) iterable); + } + + @CheckReturnValue + public static FluentIterableCompat from(final Iterable iterable) { + return (iterable instanceof FluentIterableCompat) ? ((FluentIterableCompat) iterable) : new FluentIterableCompat(iterable) { + @Override + public Iterator iterator() { + return iterable.iterator(); + } + }; + } + + @CheckReturnValue + @Override + public String toString() { + return Iterables.toString((Iterable) this.iterable); + } + + @CheckReturnValue + public final FluentIterableCompat filter(final Predicate predicate) { + return from((Iterable) Iterables.filter((Iterable) this.iterable, (Predicate) predicate)); + } + + @CheckReturnValue + public final FluentIterableCompat transform(final Function function) { + return from((Iterable) Iterables.transform((Iterable) this.iterable, (Function) function)); + } + + @CheckReturnValue + public final ImmutableList toList() { + return (ImmutableList) ImmutableList.copyOf((Iterable) this.iterable); + } +} diff --git a/src/compat/com/google/common/collect/GuavaCompat.java b/src/compat/com/google/common/collect/GuavaCompat.java new file mode 100644 index 0000000..a8d2007 --- /dev/null +++ b/src/compat/com/google/common/collect/GuavaCompat.java @@ -0,0 +1,20 @@ +package compat.com.google.common.collect; + +import com.google.common.base.*; +import javax.annotation.*; + +public class GuavaCompat { + public static > Optional getIfPresent(final Class enumClass, final String value) { + Preconditions.checkNotNull((Object) enumClass); + Preconditions.checkNotNull((Object) value); + try { + return (Optional) Optional.of(Enum.valueOf(enumClass, value)); + } catch (IllegalArgumentException iae) { + return Optional.absent(); + } + } + + public static T firstNonNull(@Nullable final T first, @Nullable final T second) { + return (T) ((first != null) ? first : Preconditions.checkNotNull(second)); + } +} diff --git a/src/config.yml b/src/config.yml new file mode 100644 index 0000000..a307a51 --- /dev/null +++ b/src/config.yml @@ -0,0 +1,72 @@ +Scoreboard_title: '&3&lHCRealms &7| &fKits' +Kitmap: + Sharpness: 1 + Protection: 1 +kits-mode: true +block-in-combat: true +SERVER_NAME: HCRealms +DONATE_URL: store.hcrealms.us +SPAWN_NO_BREAK_RADIUS: 150 +WARZONE_RADIUS: 150 +NETHER_WARZONE_RADIUS: 300 +MAX-FACTION: 25 +MAX-ALLY: 0 +DEFAULT_DEATHBAN_DURATION: 3600000 +WILDERNESS_COLOUR: DARK_GREEN +WARZONE_COLOUR: RED +SAFEZONE_COLOUR: AQUA +TEAMMATE_COLOUR: DARK_GREEN +ALLY_COLOUR: BLUE +ENEMY_COLOUR: RED +ROAD_COLOUR: GOLD +GLOWSTONE_COLOUR: GOLD +COMBATLOG_DESPAWN_DELAY_TICKS: 300 +potionLimits: + STRENGTH: 0 + INVISIBILITY: 1 + REGEN: 0 + WEAKNESS: 0 + INSTANT_DAMAGE: 0 + SLOWNESS: 1 + POISON: 1 +potionsExtendedDisallowed: + POISON + SLOWNESS +Help: +- '&8&m------------------------------------' +- '&3&lMap Infomation&7:' +- '&7Current Map&8 - &fMap 1' +- '&7Map Border&8 - &f3000' +- '&7Map Kit&8 - &f/mapkit' +- '&8&m------------------------------------' +- '&3&lUseful Commands&7:' +- '&7/coords - &fProvides the coordinates for KoTH Locations' +- '&7/teamspeak - &fProvides the Teamspeak Server IP' +- '&7/rules - &cCurrently Disabled &7(https://hcrealms.us/forums/rules/)' +- '&7/mapkit - &fProvides you with the Map Information on Enchant Limits and Potions' +- '&7/report - &fA command to report rule-breakers' +- '&7/helpop - &fAlerts online Staff Members that you are in need of + assistance' +- '&8&m------------------------------------' +- '&3&lOther infomation&7:' +- '&7Website&8 - &fwww.hcrealms.us' +- '&7Buycraft&8 - &fstore.hcrealms.us' +- '&7Teamspeak&8 - &fts.hcrealms.us' +- '&8&m------------------------------------' +Teamspeak: +- '&7Teamspeak: &fts.hcrealms.us' +teamspeak-frozen: ts.hcrealms.us +Coords: +- '&8&m----------------------------------------' +- '&6&lCoords' +- '&eSpawn: &70,0 &7(Overworld)' +- '&eNether Spawn: &70,0 &7(Nether)' +- '&eEndPortals: &70,1500,0 &7(All for quads)' +- '&8&m----------------------------------------' +spawn: + world: world + x: 0.538049846829157 + y: 69.0 + z: 0.6617853658512408 + yaw: 0.78689575 + pitch: 11.715501 diff --git a/src/gnu/trove/TByteCollection.java b/src/gnu/trove/TByteCollection.java new file mode 100644 index 0000000..77ccbe5 --- /dev/null +++ b/src/gnu/trove/TByteCollection.java @@ -0,0 +1,316 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +import java.util.Collection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TByteIterator; +import gnu.trove.procedure.TByteProcedure; + +/** + * An interface that mimics the Collection interface. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $ + */ + +public interface TByteCollection { + static final long serialVersionUID = 1L; + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + byte getNoEntryValue(); + + + /** + * Returns the number of elements in this collection (its cardinality). If this + * collection contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection (its cardinality) + */ + int size(); + + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this collection contains the specified element. + * + * @param entry an byte value + * @return true if the collection contains the specified element. + */ + boolean contains( byte entry ); + + + /** + * Creates an iterator over the values of the collection. The iterator + * supports element deletion. + * + * @return an TByteIterator value + */ + TByteIterator iterator(); + + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this collection + */ + byte[] toArray(); + + + /** + * Returns an array containing elements in this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element in + * the array immediately following the end of the collection is collection to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this collection only if the caller knows that this + * collection does not contain any elements representing null.) + * + *

If the native array is smaller than the collection size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this collection are to be + * stored. + * @return an byte[] containing all the elements in this collection + * @throws NullPointerException if the specified array is null + */ + byte[] toArray( byte[] dest ); + + + /** + * Inserts a value into the collection. + * + * @param entry a byte value + * @return true if the collection was modified by the add operation + */ + boolean add( byte entry ); + + + /** + * Removes entry from the collection. + * + * @param entry an byte value + * @return true if the collection was modified by the remove operation. + */ + boolean remove( byte entry ); + + + /** + * Tests the collection to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * TByteCollection are present. + * + * @param collection a TByteCollection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( TByteCollection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * array are present. + * + * @param array as array of byte primitives. + * @return true if all elements were present in the collection. + */ + boolean containsAll( byte[] array ); + + + /** + * Adds all of the elements in collection to the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TByteCollection to the collection. + * + * @param collection a TByteCollection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( TByteCollection collection ); + + + /** + * Adds all of the elements in the array to the collection. + * + * @param array a array of byte primitives. + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( byte[] array ); + + + /** + * Removes any values in the collection which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the collection which are not contained in + * TByteCollection. + * + * @param collection a TByteCollection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( TByteCollection collection ); + + + /** + * Removes any values in the collection which are not contained in + * array. + * + * @param array an array of byte primitives. + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( byte[] array ); + + + /** + * Removes all of the elements in collection from the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TByteCollection from the collection. + * + * @param collection a TByteCollection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( TByteCollection collection ); + + + /** + * Removes all of the elements in array from the collection. + * + * @param array an array of byte primitives. + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( byte[] array ); + + + /** + * Empties the collection. + */ + void clear(); + + + /** + * Executes procedure for each element in the collection. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the collection terminated because + * the procedure returned false for some value. + */ + boolean forEach( TByteProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality. Returns + * true if the specified object is also a collection, the two collection + * have the same size, and every member of the specified collection is + * contained in this collection (or equivalently, every member of this collection is + * contained in the specified collection). This definition ensures that the + * equals method works properly across different implementations of the + * collection interface. + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this collection + */ + boolean equals( Object o ); + + + /** + * Returns the hash code value for this collection. The hash code of a collection is + * defined to be the sum of the hash codes of the elements in the collection. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two collection s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this collection + * @see Object#equals(Object) + * @see Collection#equals(Object) + */ + int hashCode(); + + +} // TByteCollection diff --git a/src/gnu/trove/TCharCollection.java b/src/gnu/trove/TCharCollection.java new file mode 100644 index 0000000..6b49f60 --- /dev/null +++ b/src/gnu/trove/TCharCollection.java @@ -0,0 +1,316 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +import java.util.Collection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TCharIterator; +import gnu.trove.procedure.TCharProcedure; + +/** + * An interface that mimics the Collection interface. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $ + */ + +public interface TCharCollection { + static final long serialVersionUID = 1L; + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + char getNoEntryValue(); + + + /** + * Returns the number of elements in this collection (its cardinality). If this + * collection contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection (its cardinality) + */ + int size(); + + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this collection contains the specified element. + * + * @param entry an char value + * @return true if the collection contains the specified element. + */ + boolean contains( char entry ); + + + /** + * Creates an iterator over the values of the collection. The iterator + * supports element deletion. + * + * @return an TCharIterator value + */ + TCharIterator iterator(); + + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this collection + */ + char[] toArray(); + + + /** + * Returns an array containing elements in this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element in + * the array immediately following the end of the collection is collection to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this collection only if the caller knows that this + * collection does not contain any elements representing null.) + * + *

If the native array is smaller than the collection size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this collection are to be + * stored. + * @return an char[] containing all the elements in this collection + * @throws NullPointerException if the specified array is null + */ + char[] toArray( char[] dest ); + + + /** + * Inserts a value into the collection. + * + * @param entry a char value + * @return true if the collection was modified by the add operation + */ + boolean add( char entry ); + + + /** + * Removes entry from the collection. + * + * @param entry an char value + * @return true if the collection was modified by the remove operation. + */ + boolean remove( char entry ); + + + /** + * Tests the collection to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * TCharCollection are present. + * + * @param collection a TCharCollection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( TCharCollection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * array are present. + * + * @param array as array of char primitives. + * @return true if all elements were present in the collection. + */ + boolean containsAll( char[] array ); + + + /** + * Adds all of the elements in collection to the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TCharCollection to the collection. + * + * @param collection a TCharCollection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( TCharCollection collection ); + + + /** + * Adds all of the elements in the array to the collection. + * + * @param array a array of char primitives. + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( char[] array ); + + + /** + * Removes any values in the collection which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the collection which are not contained in + * TCharCollection. + * + * @param collection a TCharCollection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( TCharCollection collection ); + + + /** + * Removes any values in the collection which are not contained in + * array. + * + * @param array an array of char primitives. + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( char[] array ); + + + /** + * Removes all of the elements in collection from the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TCharCollection from the collection. + * + * @param collection a TCharCollection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( TCharCollection collection ); + + + /** + * Removes all of the elements in array from the collection. + * + * @param array an array of char primitives. + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( char[] array ); + + + /** + * Empties the collection. + */ + void clear(); + + + /** + * Executes procedure for each element in the collection. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the collection terminated because + * the procedure returned false for some value. + */ + boolean forEach( TCharProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality. Returns + * true if the specified object is also a collection, the two collection + * have the same size, and every member of the specified collection is + * contained in this collection (or equivalently, every member of this collection is + * contained in the specified collection). This definition ensures that the + * equals method works properly across different implementations of the + * collection interface. + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this collection + */ + boolean equals( Object o ); + + + /** + * Returns the hash code value for this collection. The hash code of a collection is + * defined to be the sum of the hash codes of the elements in the collection. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two collection s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this collection + * @see Object#equals(Object) + * @see Collection#equals(Object) + */ + int hashCode(); + + +} // TCharCollection diff --git a/src/gnu/trove/TCollections.java b/src/gnu/trove/TCollections.java new file mode 100644 index 0000000..8e0b22c --- /dev/null +++ b/src/gnu/trove/TCollections.java @@ -0,0 +1,4362 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import gnu.trove.list.*; +import gnu.trove.map.*; +import gnu.trove.impl.unmodifiable.*; +import gnu.trove.impl.sync.*; + +import java.util.RandomAccess; + + +/** + * Trove equivalent of the {@link java.util.Collections} class. + */ +@SuppressWarnings({}) +public class TCollections { + + // Disallow creation of instances of this class + private TCollections() { } + + +/////////////////////////// +// TUnmodifiableCollections + + /** + * Returns an unmodifiable view of the specified Trove primitive collection. This method + * allows modules to provide users with "read-only" access to internal + * collections. Query operations on the returned collection "read through" + * to the specified collection, and attempts to modify the returned + * collection, whether direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * Object's equals and hashCode methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection for which an unmodifiable view is to be + * returned. + * @return an unmodifiable view of the specified Trove primitive collection. + */ + public static TDoubleCollection unmodifiableCollection( TDoubleCollection c ) { + return new TUnmodifiableDoubleCollection( c ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive collection. This method + * allows modules to provide users with "read-only" access to internal + * collections. Query operations on the returned collection "read through" + * to the specified collection, and attempts to modify the returned + * collection, whether direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * Object's equals and hashCode methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection for which an unmodifiable view is to be + * returned. + * @return an unmodifiable view of the specified Trove primitive collection. + */ + public static TFloatCollection unmodifiableCollection( TFloatCollection c ) { + return new TUnmodifiableFloatCollection( c ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive collection. This method + * allows modules to provide users with "read-only" access to internal + * collections. Query operations on the returned collection "read through" + * to the specified collection, and attempts to modify the returned + * collection, whether direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * Object's equals and hashCode methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection for which an unmodifiable view is to be + * returned. + * @return an unmodifiable view of the specified Trove primitive collection. + */ + public static TIntCollection unmodifiableCollection( TIntCollection c ) { + return new TUnmodifiableIntCollection( c ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive collection. This method + * allows modules to provide users with "read-only" access to internal + * collections. Query operations on the returned collection "read through" + * to the specified collection, and attempts to modify the returned + * collection, whether direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * Object's equals and hashCode methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection for which an unmodifiable view is to be + * returned. + * @return an unmodifiable view of the specified Trove primitive collection. + */ + public static TLongCollection unmodifiableCollection( TLongCollection c ) { + return new TUnmodifiableLongCollection( c ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive collection. This method + * allows modules to provide users with "read-only" access to internal + * collections. Query operations on the returned collection "read through" + * to the specified collection, and attempts to modify the returned + * collection, whether direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * Object's equals and hashCode methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection for which an unmodifiable view is to be + * returned. + * @return an unmodifiable view of the specified Trove primitive collection. + */ + public static TByteCollection unmodifiableCollection( TByteCollection c ) { + return new TUnmodifiableByteCollection( c ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive collection. This method + * allows modules to provide users with "read-only" access to internal + * collections. Query operations on the returned collection "read through" + * to the specified collection, and attempts to modify the returned + * collection, whether direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * Object's equals and hashCode methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection for which an unmodifiable view is to be + * returned. + * @return an unmodifiable view of the specified Trove primitive collection. + */ + public static TShortCollection unmodifiableCollection( TShortCollection c ) { + return new TUnmodifiableShortCollection( c ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive collection. This method + * allows modules to provide users with "read-only" access to internal + * collections. Query operations on the returned collection "read through" + * to the specified collection, and attempts to modify the returned + * collection, whether direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned collection does not pass the hashCode and equals + * operations through to the backing collection, but relies on + * Object's equals and hashCode methods. This + * is necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection for which an unmodifiable view is to be + * returned. + * @return an unmodifiable view of the specified Trove primitive collection. + */ + public static TCharCollection unmodifiableCollection( TCharCollection c ) { + return new TUnmodifiableCharCollection( c ); + } + + + + /** + * Returns an unmodifiable view of the specified Trove primitive set. This method allows + * modules to provide users with "read-only" access to internal sets. + * Query operations on the returned set "read through" to the specified + * set, and attempts to modify the returned set, whether direct or via its + * iterator, result in an UnsupportedOperationException.

+ * + * The returned set will be serializable if the specified set + * is serializable. + * + * @param s the set for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive set. + */ + public static TDoubleSet unmodifiableSet( TDoubleSet s ) { + return new TUnmodifiableDoubleSet( s ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive set. This method allows + * modules to provide users with "read-only" access to internal sets. + * Query operations on the returned set "read through" to the specified + * set, and attempts to modify the returned set, whether direct or via its + * iterator, result in an UnsupportedOperationException.

+ * + * The returned set will be serializable if the specified set + * is serializable. + * + * @param s the set for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive set. + */ + public static TFloatSet unmodifiableSet( TFloatSet s ) { + return new TUnmodifiableFloatSet( s ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive set. This method allows + * modules to provide users with "read-only" access to internal sets. + * Query operations on the returned set "read through" to the specified + * set, and attempts to modify the returned set, whether direct or via its + * iterator, result in an UnsupportedOperationException.

+ * + * The returned set will be serializable if the specified set + * is serializable. + * + * @param s the set for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive set. + */ + public static TIntSet unmodifiableSet( TIntSet s ) { + return new TUnmodifiableIntSet( s ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive set. This method allows + * modules to provide users with "read-only" access to internal sets. + * Query operations on the returned set "read through" to the specified + * set, and attempts to modify the returned set, whether direct or via its + * iterator, result in an UnsupportedOperationException.

+ * + * The returned set will be serializable if the specified set + * is serializable. + * + * @param s the set for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive set. + */ + public static TLongSet unmodifiableSet( TLongSet s ) { + return new TUnmodifiableLongSet( s ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive set. This method allows + * modules to provide users with "read-only" access to internal sets. + * Query operations on the returned set "read through" to the specified + * set, and attempts to modify the returned set, whether direct or via its + * iterator, result in an UnsupportedOperationException.

+ * + * The returned set will be serializable if the specified set + * is serializable. + * + * @param s the set for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive set. + */ + public static TByteSet unmodifiableSet( TByteSet s ) { + return new TUnmodifiableByteSet( s ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive set. This method allows + * modules to provide users with "read-only" access to internal sets. + * Query operations on the returned set "read through" to the specified + * set, and attempts to modify the returned set, whether direct or via its + * iterator, result in an UnsupportedOperationException.

+ * + * The returned set will be serializable if the specified set + * is serializable. + * + * @param s the set for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive set. + */ + public static TShortSet unmodifiableSet( TShortSet s ) { + return new TUnmodifiableShortSet( s ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive set. This method allows + * modules to provide users with "read-only" access to internal sets. + * Query operations on the returned set "read through" to the specified + * set, and attempts to modify the returned set, whether direct or via its + * iterator, result in an UnsupportedOperationException.

+ * + * The returned set will be serializable if the specified set + * is serializable. + * + * @param s the set for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive set. + */ + public static TCharSet unmodifiableSet( TCharSet s ) { + return new TUnmodifiableCharSet( s ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive list. This method allows + * modules to provide users with "read-only" access to internal + * lists. Query operations on the returned list "read through" to the + * specified list, and attempts to modify the returned list, whether + * direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned list will be serializable if the specified list + * is serializable. Similarly, the returned list will implement + * {@link RandomAccess} if the specified list does. + * + * @param list the list for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive list. + */ + public static TDoubleList unmodifiableList( TDoubleList list) { + return ( list instanceof RandomAccess ? + new TUnmodifiableRandomAccessDoubleList( list ) : + new TUnmodifiableDoubleList( list ) ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive list. This method allows + * modules to provide users with "read-only" access to internal + * lists. Query operations on the returned list "read through" to the + * specified list, and attempts to modify the returned list, whether + * direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned list will be serializable if the specified list + * is serializable. Similarly, the returned list will implement + * {@link RandomAccess} if the specified list does. + * + * @param list the list for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive list. + */ + public static TFloatList unmodifiableList( TFloatList list) { + return ( list instanceof RandomAccess ? + new TUnmodifiableRandomAccessFloatList( list ) : + new TUnmodifiableFloatList( list ) ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive list. This method allows + * modules to provide users with "read-only" access to internal + * lists. Query operations on the returned list "read through" to the + * specified list, and attempts to modify the returned list, whether + * direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned list will be serializable if the specified list + * is serializable. Similarly, the returned list will implement + * {@link RandomAccess} if the specified list does. + * + * @param list the list for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive list. + */ + public static TIntList unmodifiableList( TIntList list) { + return ( list instanceof RandomAccess ? + new TUnmodifiableRandomAccessIntList( list ) : + new TUnmodifiableIntList( list ) ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive list. This method allows + * modules to provide users with "read-only" access to internal + * lists. Query operations on the returned list "read through" to the + * specified list, and attempts to modify the returned list, whether + * direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned list will be serializable if the specified list + * is serializable. Similarly, the returned list will implement + * {@link RandomAccess} if the specified list does. + * + * @param list the list for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive list. + */ + public static TLongList unmodifiableList( TLongList list) { + return ( list instanceof RandomAccess ? + new TUnmodifiableRandomAccessLongList( list ) : + new TUnmodifiableLongList( list ) ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive list. This method allows + * modules to provide users with "read-only" access to internal + * lists. Query operations on the returned list "read through" to the + * specified list, and attempts to modify the returned list, whether + * direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned list will be serializable if the specified list + * is serializable. Similarly, the returned list will implement + * {@link RandomAccess} if the specified list does. + * + * @param list the list for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive list. + */ + public static TByteList unmodifiableList( TByteList list) { + return ( list instanceof RandomAccess ? + new TUnmodifiableRandomAccessByteList( list ) : + new TUnmodifiableByteList( list ) ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive list. This method allows + * modules to provide users with "read-only" access to internal + * lists. Query operations on the returned list "read through" to the + * specified list, and attempts to modify the returned list, whether + * direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned list will be serializable if the specified list + * is serializable. Similarly, the returned list will implement + * {@link RandomAccess} if the specified list does. + * + * @param list the list for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive list. + */ + public static TShortList unmodifiableList( TShortList list) { + return ( list instanceof RandomAccess ? + new TUnmodifiableRandomAccessShortList( list ) : + new TUnmodifiableShortList( list ) ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive list. This method allows + * modules to provide users with "read-only" access to internal + * lists. Query operations on the returned list "read through" to the + * specified list, and attempts to modify the returned list, whether + * direct or via its iterator, result in an + * UnsupportedOperationException.

+ * + * The returned list will be serializable if the specified list + * is serializable. Similarly, the returned list will implement + * {@link RandomAccess} if the specified list does. + * + * @param list the list for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive list. + */ + public static TCharList unmodifiableList( TCharList list) { + return ( list instanceof RandomAccess ? + new TUnmodifiableRandomAccessCharList( list ) : + new TUnmodifiableCharList( list ) ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleDoubleMap unmodifiableMap( TDoubleDoubleMap m ) { + return new TUnmodifiableDoubleDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleFloatMap unmodifiableMap( TDoubleFloatMap m ) { + return new TUnmodifiableDoubleFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleIntMap unmodifiableMap( TDoubleIntMap m ) { + return new TUnmodifiableDoubleIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleLongMap unmodifiableMap( TDoubleLongMap m ) { + return new TUnmodifiableDoubleLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleByteMap unmodifiableMap( TDoubleByteMap m ) { + return new TUnmodifiableDoubleByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleShortMap unmodifiableMap( TDoubleShortMap m ) { + return new TUnmodifiableDoubleShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleCharMap unmodifiableMap( TDoubleCharMap m ) { + return new TUnmodifiableDoubleCharMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatDoubleMap unmodifiableMap( TFloatDoubleMap m ) { + return new TUnmodifiableFloatDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatFloatMap unmodifiableMap( TFloatFloatMap m ) { + return new TUnmodifiableFloatFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatIntMap unmodifiableMap( TFloatIntMap m ) { + return new TUnmodifiableFloatIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatLongMap unmodifiableMap( TFloatLongMap m ) { + return new TUnmodifiableFloatLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatByteMap unmodifiableMap( TFloatByteMap m ) { + return new TUnmodifiableFloatByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatShortMap unmodifiableMap( TFloatShortMap m ) { + return new TUnmodifiableFloatShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatCharMap unmodifiableMap( TFloatCharMap m ) { + return new TUnmodifiableFloatCharMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntDoubleMap unmodifiableMap( TIntDoubleMap m ) { + return new TUnmodifiableIntDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntFloatMap unmodifiableMap( TIntFloatMap m ) { + return new TUnmodifiableIntFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntIntMap unmodifiableMap( TIntIntMap m ) { + return new TUnmodifiableIntIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntLongMap unmodifiableMap( TIntLongMap m ) { + return new TUnmodifiableIntLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntByteMap unmodifiableMap( TIntByteMap m ) { + return new TUnmodifiableIntByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntShortMap unmodifiableMap( TIntShortMap m ) { + return new TUnmodifiableIntShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntCharMap unmodifiableMap( TIntCharMap m ) { + return new TUnmodifiableIntCharMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongDoubleMap unmodifiableMap( TLongDoubleMap m ) { + return new TUnmodifiableLongDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongFloatMap unmodifiableMap( TLongFloatMap m ) { + return new TUnmodifiableLongFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongIntMap unmodifiableMap( TLongIntMap m ) { + return new TUnmodifiableLongIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongLongMap unmodifiableMap( TLongLongMap m ) { + return new TUnmodifiableLongLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongByteMap unmodifiableMap( TLongByteMap m ) { + return new TUnmodifiableLongByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongShortMap unmodifiableMap( TLongShortMap m ) { + return new TUnmodifiableLongShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongCharMap unmodifiableMap( TLongCharMap m ) { + return new TUnmodifiableLongCharMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteDoubleMap unmodifiableMap( TByteDoubleMap m ) { + return new TUnmodifiableByteDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteFloatMap unmodifiableMap( TByteFloatMap m ) { + return new TUnmodifiableByteFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteIntMap unmodifiableMap( TByteIntMap m ) { + return new TUnmodifiableByteIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteLongMap unmodifiableMap( TByteLongMap m ) { + return new TUnmodifiableByteLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteByteMap unmodifiableMap( TByteByteMap m ) { + return new TUnmodifiableByteByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteShortMap unmodifiableMap( TByteShortMap m ) { + return new TUnmodifiableByteShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteCharMap unmodifiableMap( TByteCharMap m ) { + return new TUnmodifiableByteCharMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortDoubleMap unmodifiableMap( TShortDoubleMap m ) { + return new TUnmodifiableShortDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortFloatMap unmodifiableMap( TShortFloatMap m ) { + return new TUnmodifiableShortFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortIntMap unmodifiableMap( TShortIntMap m ) { + return new TUnmodifiableShortIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortLongMap unmodifiableMap( TShortLongMap m ) { + return new TUnmodifiableShortLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortByteMap unmodifiableMap( TShortByteMap m ) { + return new TUnmodifiableShortByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortShortMap unmodifiableMap( TShortShortMap m ) { + return new TUnmodifiableShortShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortCharMap unmodifiableMap( TShortCharMap m ) { + return new TUnmodifiableShortCharMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharDoubleMap unmodifiableMap( TCharDoubleMap m ) { + return new TUnmodifiableCharDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharFloatMap unmodifiableMap( TCharFloatMap m ) { + return new TUnmodifiableCharFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharIntMap unmodifiableMap( TCharIntMap m ) { + return new TUnmodifiableCharIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharLongMap unmodifiableMap( TCharLongMap m ) { + return new TUnmodifiableCharLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharByteMap unmodifiableMap( TCharByteMap m ) { + return new TUnmodifiableCharByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharShortMap unmodifiableMap( TCharShortMap m ) { + return new TUnmodifiableCharShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharCharMap unmodifiableMap( TCharCharMap m ) { + return new TUnmodifiableCharCharMap( m ); + } + + + /** + * Returns an unmodifiable view of the specified Trove primitive/Object map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TDoubleObjectMap unmodifiableMap( TDoubleObjectMap m ) { + return new TUnmodifiableDoubleObjectMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/Object map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TFloatObjectMap unmodifiableMap( TFloatObjectMap m ) { + return new TUnmodifiableFloatObjectMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/Object map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TIntObjectMap unmodifiableMap( TIntObjectMap m ) { + return new TUnmodifiableIntObjectMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/Object map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TLongObjectMap unmodifiableMap( TLongObjectMap m ) { + return new TUnmodifiableLongObjectMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/Object map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TByteObjectMap unmodifiableMap( TByteObjectMap m ) { + return new TUnmodifiableByteObjectMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/Object map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TShortObjectMap unmodifiableMap( TShortObjectMap m ) { + return new TUnmodifiableShortObjectMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove primitive/Object map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TCharObjectMap unmodifiableMap( TCharObjectMap m ) { + return new TUnmodifiableCharObjectMap( m ); + } + + + /** + * Returns an unmodifiable view of the specified Trove Object/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TObjectDoubleMap unmodifiableMap( TObjectDoubleMap m ) { + return new TUnmodifiableObjectDoubleMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove Object/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TObjectFloatMap unmodifiableMap( TObjectFloatMap m ) { + return new TUnmodifiableObjectFloatMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove Object/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TObjectIntMap unmodifiableMap( TObjectIntMap m ) { + return new TUnmodifiableObjectIntMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove Object/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TObjectLongMap unmodifiableMap( TObjectLongMap m ) { + return new TUnmodifiableObjectLongMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove Object/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TObjectByteMap unmodifiableMap( TObjectByteMap m ) { + return new TUnmodifiableObjectByteMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove Object/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TObjectShortMap unmodifiableMap( TObjectShortMap m ) { + return new TUnmodifiableObjectShortMap( m ); + } + + /** + * Returns an unmodifiable view of the specified Trove Object/primitive map. This method + * allows modules to provide users with "read-only" access to internal + * maps. Query operations on the returned map "read through" + * to the specified map, and attempts to modify the returned + * map, whether direct or via its collection views, result in an + * UnsupportedOperationException.

+ * + * The returned map will be serializable if the specified map + * is serializable. + * + * @param m the map for which an unmodifiable view is to be returned. + * @return an unmodifiable view of the specified Trove primitive/primitive map. + */ + public static TObjectCharMap unmodifiableMap( TObjectCharMap m ) { + return new TUnmodifiableObjectCharMap( m ); + } + + + +/////////////////////////// +// TSynchronizedCollections + + /** + * Returns a synchronized (thread-safe) Trove collection backed by the specified + * Trove collection. In order to guarantee serial access, it is critical that + * all access to the backing collection is accomplished + * through the returned collection.

+ * + * It is imperative that the user manually synchronize on the returned + * collection when iterating over it: + *

+     *  TDoubleCollection c = TCollections.synchronizedCollection( myCollection );
+     *     ...
+     *  synchronized( c ) {
+     *      TDoubleIterator i = c.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *         foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned collection does not pass the hashCode + * and equals operations through to the backing collection, but + * relies on Object's equals and hashCode methods. This is + * necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection to be "wrapped" in a synchronized collection. + * @return a synchronized view of the specified collection. + */ + public static TDoubleCollection synchronizedCollection( TDoubleCollection c ) { + return new TSynchronizedDoubleCollection(c); + } + + static TDoubleCollection synchronizedCollection( TDoubleCollection c, Object mutex ) { + return new TSynchronizedDoubleCollection( c, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove collection backed by the specified + * Trove collection. In order to guarantee serial access, it is critical that + * all access to the backing collection is accomplished + * through the returned collection.

+ * + * It is imperative that the user manually synchronize on the returned + * collection when iterating over it: + *

+     *  TFloatCollection c = TCollections.synchronizedCollection( myCollection );
+     *     ...
+     *  synchronized( c ) {
+     *      TFloatIterator i = c.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *         foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned collection does not pass the hashCode + * and equals operations through to the backing collection, but + * relies on Object's equals and hashCode methods. This is + * necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection to be "wrapped" in a synchronized collection. + * @return a synchronized view of the specified collection. + */ + public static TFloatCollection synchronizedCollection( TFloatCollection c ) { + return new TSynchronizedFloatCollection(c); + } + + static TFloatCollection synchronizedCollection( TFloatCollection c, Object mutex ) { + return new TSynchronizedFloatCollection( c, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove collection backed by the specified + * Trove collection. In order to guarantee serial access, it is critical that + * all access to the backing collection is accomplished + * through the returned collection.

+ * + * It is imperative that the user manually synchronize on the returned + * collection when iterating over it: + *

+     *  TIntCollection c = TCollections.synchronizedCollection( myCollection );
+     *     ...
+     *  synchronized( c ) {
+     *      TIntIterator i = c.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *         foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned collection does not pass the hashCode + * and equals operations through to the backing collection, but + * relies on Object's equals and hashCode methods. This is + * necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection to be "wrapped" in a synchronized collection. + * @return a synchronized view of the specified collection. + */ + public static TIntCollection synchronizedCollection( TIntCollection c ) { + return new TSynchronizedIntCollection(c); + } + + static TIntCollection synchronizedCollection( TIntCollection c, Object mutex ) { + return new TSynchronizedIntCollection( c, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove collection backed by the specified + * Trove collection. In order to guarantee serial access, it is critical that + * all access to the backing collection is accomplished + * through the returned collection.

+ * + * It is imperative that the user manually synchronize on the returned + * collection when iterating over it: + *

+     *  TLongCollection c = TCollections.synchronizedCollection( myCollection );
+     *     ...
+     *  synchronized( c ) {
+     *      TLongIterator i = c.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *         foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned collection does not pass the hashCode + * and equals operations through to the backing collection, but + * relies on Object's equals and hashCode methods. This is + * necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection to be "wrapped" in a synchronized collection. + * @return a synchronized view of the specified collection. + */ + public static TLongCollection synchronizedCollection( TLongCollection c ) { + return new TSynchronizedLongCollection(c); + } + + static TLongCollection synchronizedCollection( TLongCollection c, Object mutex ) { + return new TSynchronizedLongCollection( c, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove collection backed by the specified + * Trove collection. In order to guarantee serial access, it is critical that + * all access to the backing collection is accomplished + * through the returned collection.

+ * + * It is imperative that the user manually synchronize on the returned + * collection when iterating over it: + *

+     *  TByteCollection c = TCollections.synchronizedCollection( myCollection );
+     *     ...
+     *  synchronized( c ) {
+     *      TByteIterator i = c.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *         foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned collection does not pass the hashCode + * and equals operations through to the backing collection, but + * relies on Object's equals and hashCode methods. This is + * necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection to be "wrapped" in a synchronized collection. + * @return a synchronized view of the specified collection. + */ + public static TByteCollection synchronizedCollection( TByteCollection c ) { + return new TSynchronizedByteCollection(c); + } + + static TByteCollection synchronizedCollection( TByteCollection c, Object mutex ) { + return new TSynchronizedByteCollection( c, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove collection backed by the specified + * Trove collection. In order to guarantee serial access, it is critical that + * all access to the backing collection is accomplished + * through the returned collection.

+ * + * It is imperative that the user manually synchronize on the returned + * collection when iterating over it: + *

+     *  TShortCollection c = TCollections.synchronizedCollection( myCollection );
+     *     ...
+     *  synchronized( c ) {
+     *      TShortIterator i = c.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *         foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned collection does not pass the hashCode + * and equals operations through to the backing collection, but + * relies on Object's equals and hashCode methods. This is + * necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection to be "wrapped" in a synchronized collection. + * @return a synchronized view of the specified collection. + */ + public static TShortCollection synchronizedCollection( TShortCollection c ) { + return new TSynchronizedShortCollection(c); + } + + static TShortCollection synchronizedCollection( TShortCollection c, Object mutex ) { + return new TSynchronizedShortCollection( c, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove collection backed by the specified + * Trove collection. In order to guarantee serial access, it is critical that + * all access to the backing collection is accomplished + * through the returned collection.

+ * + * It is imperative that the user manually synchronize on the returned + * collection when iterating over it: + *

+     *  TCharCollection c = TCollections.synchronizedCollection( myCollection );
+     *     ...
+     *  synchronized( c ) {
+     *      TCharIterator i = c.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *         foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned collection does not pass the hashCode + * and equals operations through to the backing collection, but + * relies on Object's equals and hashCode methods. This is + * necessary to preserve the contracts of these operations in the case + * that the backing collection is a set or a list.

+ * + * The returned collection will be serializable if the specified collection + * is serializable. + * + * @param c the collection to be "wrapped" in a synchronized collection. + * @return a synchronized view of the specified collection. + */ + public static TCharCollection synchronizedCollection( TCharCollection c ) { + return new TSynchronizedCharCollection(c); + } + + static TCharCollection synchronizedCollection( TCharCollection c, Object mutex ) { + return new TSynchronizedCharCollection( c, mutex ); + } + + + /** + * Returns a synchronized (thread-safe) Trove set backed by the specified + * set. In order to guarantee serial access, it is critical that + * all access to the backing set is accomplished + * through the returned set.

+ * + * It is imperative that the user manually synchronize on the returned + * set when iterating over it: + *

+     *  TDoubleSet s = TCollections.synchronizedSet( new TDoubleHashSet() );
+     *      ...
+     *  synchronized(s) {
+     *      TDoubleIterator i = s.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned set will be serializable if the specified set is + * serializable. + * + * @param s the set to be "wrapped" in a synchronized set. + * @return a synchronized view of the specified set. + */ + public static TDoubleSet synchronizedSet( TDoubleSet s ) { + return new TSynchronizedDoubleSet( s ); + } + + static TDoubleSet synchronizedSet( TDoubleSet s, Object mutex ) { + return new TSynchronizedDoubleSet( s, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove set backed by the specified + * set. In order to guarantee serial access, it is critical that + * all access to the backing set is accomplished + * through the returned set.

+ * + * It is imperative that the user manually synchronize on the returned + * set when iterating over it: + *

+     *  TFloatSet s = TCollections.synchronizedSet( new TFloatHashSet() );
+     *      ...
+     *  synchronized(s) {
+     *      TFloatIterator i = s.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned set will be serializable if the specified set is + * serializable. + * + * @param s the set to be "wrapped" in a synchronized set. + * @return a synchronized view of the specified set. + */ + public static TFloatSet synchronizedSet( TFloatSet s ) { + return new TSynchronizedFloatSet( s ); + } + + static TFloatSet synchronizedSet( TFloatSet s, Object mutex ) { + return new TSynchronizedFloatSet( s, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove set backed by the specified + * set. In order to guarantee serial access, it is critical that + * all access to the backing set is accomplished + * through the returned set.

+ * + * It is imperative that the user manually synchronize on the returned + * set when iterating over it: + *

+     *  TIntSet s = TCollections.synchronizedSet( new TIntHashSet() );
+     *      ...
+     *  synchronized(s) {
+     *      TIntIterator i = s.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned set will be serializable if the specified set is + * serializable. + * + * @param s the set to be "wrapped" in a synchronized set. + * @return a synchronized view of the specified set. + */ + public static TIntSet synchronizedSet( TIntSet s ) { + return new TSynchronizedIntSet( s ); + } + + static TIntSet synchronizedSet( TIntSet s, Object mutex ) { + return new TSynchronizedIntSet( s, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove set backed by the specified + * set. In order to guarantee serial access, it is critical that + * all access to the backing set is accomplished + * through the returned set.

+ * + * It is imperative that the user manually synchronize on the returned + * set when iterating over it: + *

+     *  TLongSet s = TCollections.synchronizedSet( new TLongHashSet() );
+     *      ...
+     *  synchronized(s) {
+     *      TLongIterator i = s.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned set will be serializable if the specified set is + * serializable. + * + * @param s the set to be "wrapped" in a synchronized set. + * @return a synchronized view of the specified set. + */ + public static TLongSet synchronizedSet( TLongSet s ) { + return new TSynchronizedLongSet( s ); + } + + static TLongSet synchronizedSet( TLongSet s, Object mutex ) { + return new TSynchronizedLongSet( s, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove set backed by the specified + * set. In order to guarantee serial access, it is critical that + * all access to the backing set is accomplished + * through the returned set.

+ * + * It is imperative that the user manually synchronize on the returned + * set when iterating over it: + *

+     *  TByteSet s = TCollections.synchronizedSet( new TByteHashSet() );
+     *      ...
+     *  synchronized(s) {
+     *      TByteIterator i = s.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned set will be serializable if the specified set is + * serializable. + * + * @param s the set to be "wrapped" in a synchronized set. + * @return a synchronized view of the specified set. + */ + public static TByteSet synchronizedSet( TByteSet s ) { + return new TSynchronizedByteSet( s ); + } + + static TByteSet synchronizedSet( TByteSet s, Object mutex ) { + return new TSynchronizedByteSet( s, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove set backed by the specified + * set. In order to guarantee serial access, it is critical that + * all access to the backing set is accomplished + * through the returned set.

+ * + * It is imperative that the user manually synchronize on the returned + * set when iterating over it: + *

+     *  TShortSet s = TCollections.synchronizedSet( new TShortHashSet() );
+     *      ...
+     *  synchronized(s) {
+     *      TShortIterator i = s.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned set will be serializable if the specified set is + * serializable. + * + * @param s the set to be "wrapped" in a synchronized set. + * @return a synchronized view of the specified set. + */ + public static TShortSet synchronizedSet( TShortSet s ) { + return new TSynchronizedShortSet( s ); + } + + static TShortSet synchronizedSet( TShortSet s, Object mutex ) { + return new TSynchronizedShortSet( s, mutex ); + } + + /** + * Returns a synchronized (thread-safe) Trove set backed by the specified + * set. In order to guarantee serial access, it is critical that + * all access to the backing set is accomplished + * through the returned set.

+ * + * It is imperative that the user manually synchronize on the returned + * set when iterating over it: + *

+     *  TCharSet s = TCollections.synchronizedSet( new TCharHashSet() );
+     *      ...
+     *  synchronized(s) {
+     *      TCharIterator i = s.iterator(); // Must be in the synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned set will be serializable if the specified set is + * serializable. + * + * @param s the set to be "wrapped" in a synchronized set. + * @return a synchronized view of the specified set. + */ + public static TCharSet synchronizedSet( TCharSet s ) { + return new TSynchronizedCharSet( s ); + } + + static TCharSet synchronizedSet( TCharSet s, Object mutex ) { + return new TSynchronizedCharSet( s, mutex ); + } + + + /** + * Returns a synchronized (thread-safe) Trove list backed by the specified + * list. In order to guarantee serial access, it is critical that + * all access to the backing list is accomplished + * through the returned list.

+ * + * It is imperative that the user manually synchronize on the returned + * list when iterating over it: + *

+     *  TDoubleList list = TCollections.synchronizedList( new TDoubleArrayList() );
+     *      ...
+     *  synchronized( list ) {
+     *      TDoubleIterator i = list.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned list will be serializable if the specified list is + * serializable. + * + * @param list the list to be "wrapped" in a synchronized list. + * @return a synchronized view of the specified list. + */ + public static TDoubleList synchronizedList( TDoubleList list ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessDoubleList( list ) : + new TSynchronizedDoubleList( list ) ); + } + + static TDoubleList synchronizedList( TDoubleList list, Object mutex ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessDoubleList( list, mutex ) : + new TSynchronizedDoubleList( list, mutex ) ); + } + + /** + * Returns a synchronized (thread-safe) Trove list backed by the specified + * list. In order to guarantee serial access, it is critical that + * all access to the backing list is accomplished + * through the returned list.

+ * + * It is imperative that the user manually synchronize on the returned + * list when iterating over it: + *

+     *  TFloatList list = TCollections.synchronizedList( new TFloatArrayList() );
+     *      ...
+     *  synchronized( list ) {
+     *      TFloatIterator i = list.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned list will be serializable if the specified list is + * serializable. + * + * @param list the list to be "wrapped" in a synchronized list. + * @return a synchronized view of the specified list. + */ + public static TFloatList synchronizedList( TFloatList list ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessFloatList( list ) : + new TSynchronizedFloatList( list ) ); + } + + static TFloatList synchronizedList( TFloatList list, Object mutex ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessFloatList( list, mutex ) : + new TSynchronizedFloatList( list, mutex ) ); + } + + /** + * Returns a synchronized (thread-safe) Trove list backed by the specified + * list. In order to guarantee serial access, it is critical that + * all access to the backing list is accomplished + * through the returned list.

+ * + * It is imperative that the user manually synchronize on the returned + * list when iterating over it: + *

+     *  TIntList list = TCollections.synchronizedList( new TIntArrayList() );
+     *      ...
+     *  synchronized( list ) {
+     *      TIntIterator i = list.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned list will be serializable if the specified list is + * serializable. + * + * @param list the list to be "wrapped" in a synchronized list. + * @return a synchronized view of the specified list. + */ + public static TIntList synchronizedList( TIntList list ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessIntList( list ) : + new TSynchronizedIntList( list ) ); + } + + static TIntList synchronizedList( TIntList list, Object mutex ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessIntList( list, mutex ) : + new TSynchronizedIntList( list, mutex ) ); + } + + /** + * Returns a synchronized (thread-safe) Trove list backed by the specified + * list. In order to guarantee serial access, it is critical that + * all access to the backing list is accomplished + * through the returned list.

+ * + * It is imperative that the user manually synchronize on the returned + * list when iterating over it: + *

+     *  TLongList list = TCollections.synchronizedList( new TLongArrayList() );
+     *      ...
+     *  synchronized( list ) {
+     *      TLongIterator i = list.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned list will be serializable if the specified list is + * serializable. + * + * @param list the list to be "wrapped" in a synchronized list. + * @return a synchronized view of the specified list. + */ + public static TLongList synchronizedList( TLongList list ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessLongList( list ) : + new TSynchronizedLongList( list ) ); + } + + static TLongList synchronizedList( TLongList list, Object mutex ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessLongList( list, mutex ) : + new TSynchronizedLongList( list, mutex ) ); + } + + /** + * Returns a synchronized (thread-safe) Trove list backed by the specified + * list. In order to guarantee serial access, it is critical that + * all access to the backing list is accomplished + * through the returned list.

+ * + * It is imperative that the user manually synchronize on the returned + * list when iterating over it: + *

+     *  TByteList list = TCollections.synchronizedList( new TByteArrayList() );
+     *      ...
+     *  synchronized( list ) {
+     *      TByteIterator i = list.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned list will be serializable if the specified list is + * serializable. + * + * @param list the list to be "wrapped" in a synchronized list. + * @return a synchronized view of the specified list. + */ + public static TByteList synchronizedList( TByteList list ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessByteList( list ) : + new TSynchronizedByteList( list ) ); + } + + static TByteList synchronizedList( TByteList list, Object mutex ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessByteList( list, mutex ) : + new TSynchronizedByteList( list, mutex ) ); + } + + /** + * Returns a synchronized (thread-safe) Trove list backed by the specified + * list. In order to guarantee serial access, it is critical that + * all access to the backing list is accomplished + * through the returned list.

+ * + * It is imperative that the user manually synchronize on the returned + * list when iterating over it: + *

+     *  TShortList list = TCollections.synchronizedList( new TShortArrayList() );
+     *      ...
+     *  synchronized( list ) {
+     *      TShortIterator i = list.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned list will be serializable if the specified list is + * serializable. + * + * @param list the list to be "wrapped" in a synchronized list. + * @return a synchronized view of the specified list. + */ + public static TShortList synchronizedList( TShortList list ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessShortList( list ) : + new TSynchronizedShortList( list ) ); + } + + static TShortList synchronizedList( TShortList list, Object mutex ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessShortList( list, mutex ) : + new TSynchronizedShortList( list, mutex ) ); + } + + /** + * Returns a synchronized (thread-safe) Trove list backed by the specified + * list. In order to guarantee serial access, it is critical that + * all access to the backing list is accomplished + * through the returned list.

+ * + * It is imperative that the user manually synchronize on the returned + * list when iterating over it: + *

+     *  TCharList list = TCollections.synchronizedList( new TCharArrayList() );
+     *      ...
+     *  synchronized( list ) {
+     *      TCharIterator i = list.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned list will be serializable if the specified list is + * serializable. + * + * @param list the list to be "wrapped" in a synchronized list. + * @return a synchronized view of the specified list. + */ + public static TCharList synchronizedList( TCharList list ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessCharList( list ) : + new TSynchronizedCharList( list ) ); + } + + static TCharList synchronizedList( TCharList list, Object mutex ) { + return ( list instanceof RandomAccess ? + new TSynchronizedRandomAccessCharList( list, mutex ) : + new TSynchronizedCharList( list, mutex ) ); + } + + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleDoubleMap m = TCollections.synchronizedMap( new TDoubleDoubleHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleDoubleMap synchronizedMap( TDoubleDoubleMap m ) { + return new TSynchronizedDoubleDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleFloatMap m = TCollections.synchronizedMap( new TDoubleFloatHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleFloatMap synchronizedMap( TDoubleFloatMap m ) { + return new TSynchronizedDoubleFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleIntMap m = TCollections.synchronizedMap( new TDoubleIntHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleIntMap synchronizedMap( TDoubleIntMap m ) { + return new TSynchronizedDoubleIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleLongMap m = TCollections.synchronizedMap( new TDoubleLongHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleLongMap synchronizedMap( TDoubleLongMap m ) { + return new TSynchronizedDoubleLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleByteMap m = TCollections.synchronizedMap( new TDoubleByteHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleByteMap synchronizedMap( TDoubleByteMap m ) { + return new TSynchronizedDoubleByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleShortMap m = TCollections.synchronizedMap( new TDoubleShortHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleShortMap synchronizedMap( TDoubleShortMap m ) { + return new TSynchronizedDoubleShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleCharMap m = TCollections.synchronizedMap( new TDoubleCharHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleCharMap synchronizedMap( TDoubleCharMap m ) { + return new TSynchronizedDoubleCharMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatDoubleMap m = TCollections.synchronizedMap( new TFloatDoubleHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatDoubleMap synchronizedMap( TFloatDoubleMap m ) { + return new TSynchronizedFloatDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatFloatMap m = TCollections.synchronizedMap( new TFloatFloatHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatFloatMap synchronizedMap( TFloatFloatMap m ) { + return new TSynchronizedFloatFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatIntMap m = TCollections.synchronizedMap( new TFloatIntHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatIntMap synchronizedMap( TFloatIntMap m ) { + return new TSynchronizedFloatIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatLongMap m = TCollections.synchronizedMap( new TFloatLongHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatLongMap synchronizedMap( TFloatLongMap m ) { + return new TSynchronizedFloatLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatByteMap m = TCollections.synchronizedMap( new TFloatByteHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatByteMap synchronizedMap( TFloatByteMap m ) { + return new TSynchronizedFloatByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatShortMap m = TCollections.synchronizedMap( new TFloatShortHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatShortMap synchronizedMap( TFloatShortMap m ) { + return new TSynchronizedFloatShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatCharMap m = TCollections.synchronizedMap( new TFloatCharHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatCharMap synchronizedMap( TFloatCharMap m ) { + return new TSynchronizedFloatCharMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntDoubleMap m = TCollections.synchronizedMap( new TIntDoubleHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntDoubleMap synchronizedMap( TIntDoubleMap m ) { + return new TSynchronizedIntDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntFloatMap m = TCollections.synchronizedMap( new TIntFloatHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntFloatMap synchronizedMap( TIntFloatMap m ) { + return new TSynchronizedIntFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntIntMap m = TCollections.synchronizedMap( new TIntIntHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntIntMap synchronizedMap( TIntIntMap m ) { + return new TSynchronizedIntIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntLongMap m = TCollections.synchronizedMap( new TIntLongHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntLongMap synchronizedMap( TIntLongMap m ) { + return new TSynchronizedIntLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntByteMap m = TCollections.synchronizedMap( new TIntByteHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntByteMap synchronizedMap( TIntByteMap m ) { + return new TSynchronizedIntByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntShortMap m = TCollections.synchronizedMap( new TIntShortHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntShortMap synchronizedMap( TIntShortMap m ) { + return new TSynchronizedIntShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntCharMap m = TCollections.synchronizedMap( new TIntCharHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntCharMap synchronizedMap( TIntCharMap m ) { + return new TSynchronizedIntCharMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongDoubleMap m = TCollections.synchronizedMap( new TLongDoubleHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongDoubleMap synchronizedMap( TLongDoubleMap m ) { + return new TSynchronizedLongDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongFloatMap m = TCollections.synchronizedMap( new TLongFloatHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongFloatMap synchronizedMap( TLongFloatMap m ) { + return new TSynchronizedLongFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongIntMap m = TCollections.synchronizedMap( new TLongIntHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongIntMap synchronizedMap( TLongIntMap m ) { + return new TSynchronizedLongIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongLongMap m = TCollections.synchronizedMap( new TLongLongHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongLongMap synchronizedMap( TLongLongMap m ) { + return new TSynchronizedLongLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongByteMap m = TCollections.synchronizedMap( new TLongByteHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongByteMap synchronizedMap( TLongByteMap m ) { + return new TSynchronizedLongByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongShortMap m = TCollections.synchronizedMap( new TLongShortHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongShortMap synchronizedMap( TLongShortMap m ) { + return new TSynchronizedLongShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongCharMap m = TCollections.synchronizedMap( new TLongCharHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongCharMap synchronizedMap( TLongCharMap m ) { + return new TSynchronizedLongCharMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteDoubleMap m = TCollections.synchronizedMap( new TByteDoubleHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteDoubleMap synchronizedMap( TByteDoubleMap m ) { + return new TSynchronizedByteDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteFloatMap m = TCollections.synchronizedMap( new TByteFloatHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteFloatMap synchronizedMap( TByteFloatMap m ) { + return new TSynchronizedByteFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteIntMap m = TCollections.synchronizedMap( new TByteIntHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteIntMap synchronizedMap( TByteIntMap m ) { + return new TSynchronizedByteIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteLongMap m = TCollections.synchronizedMap( new TByteLongHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteLongMap synchronizedMap( TByteLongMap m ) { + return new TSynchronizedByteLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteByteMap m = TCollections.synchronizedMap( new TByteByteHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteByteMap synchronizedMap( TByteByteMap m ) { + return new TSynchronizedByteByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteShortMap m = TCollections.synchronizedMap( new TByteShortHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteShortMap synchronizedMap( TByteShortMap m ) { + return new TSynchronizedByteShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteCharMap m = TCollections.synchronizedMap( new TByteCharHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteCharMap synchronizedMap( TByteCharMap m ) { + return new TSynchronizedByteCharMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortDoubleMap m = TCollections.synchronizedMap( new TShortDoubleHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortDoubleMap synchronizedMap( TShortDoubleMap m ) { + return new TSynchronizedShortDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortFloatMap m = TCollections.synchronizedMap( new TShortFloatHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortFloatMap synchronizedMap( TShortFloatMap m ) { + return new TSynchronizedShortFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortIntMap m = TCollections.synchronizedMap( new TShortIntHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortIntMap synchronizedMap( TShortIntMap m ) { + return new TSynchronizedShortIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortLongMap m = TCollections.synchronizedMap( new TShortLongHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortLongMap synchronizedMap( TShortLongMap m ) { + return new TSynchronizedShortLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortByteMap m = TCollections.synchronizedMap( new TShortByteHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortByteMap synchronizedMap( TShortByteMap m ) { + return new TSynchronizedShortByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortShortMap m = TCollections.synchronizedMap( new TShortShortHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortShortMap synchronizedMap( TShortShortMap m ) { + return new TSynchronizedShortShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortCharMap m = TCollections.synchronizedMap( new TShortCharHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortCharMap synchronizedMap( TShortCharMap m ) { + return new TSynchronizedShortCharMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharDoubleMap m = TCollections.synchronizedMap( new TCharDoubleHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharDoubleMap synchronizedMap( TCharDoubleMap m ) { + return new TSynchronizedCharDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharFloatMap m = TCollections.synchronizedMap( new TCharFloatHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharFloatMap synchronizedMap( TCharFloatMap m ) { + return new TSynchronizedCharFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharIntMap m = TCollections.synchronizedMap( new TCharIntHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharIntMap synchronizedMap( TCharIntMap m ) { + return new TSynchronizedCharIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharLongMap m = TCollections.synchronizedMap( new TCharLongHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharLongMap synchronizedMap( TCharLongMap m ) { + return new TSynchronizedCharLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharByteMap m = TCollections.synchronizedMap( new TCharByteHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharByteMap synchronizedMap( TCharByteMap m ) { + return new TSynchronizedCharByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharShortMap m = TCollections.synchronizedMap( new TCharShortHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharShortMap synchronizedMap( TCharShortMap m ) { + return new TSynchronizedCharShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharCharMap m = TCollections.synchronizedMap( new TCharCharHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharCharMap synchronizedMap( TCharCharMap m ) { + return new TSynchronizedCharCharMap( m ); + } + + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TDoubleObjectMap m = TCollections.synchronizedMap( new TDoubleObjectHashMap() );
+     *      ...
+     *  TDoubleSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TDoubleIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TDoubleObjectMap synchronizedMap( TDoubleObjectMap m ) { + return new TSynchronizedDoubleObjectMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TFloatObjectMap m = TCollections.synchronizedMap( new TFloatObjectHashMap() );
+     *      ...
+     *  TFloatSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TFloatIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TFloatObjectMap synchronizedMap( TFloatObjectMap m ) { + return new TSynchronizedFloatObjectMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TIntObjectMap m = TCollections.synchronizedMap( new TIntObjectHashMap() );
+     *      ...
+     *  TIntSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TIntIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TIntObjectMap synchronizedMap( TIntObjectMap m ) { + return new TSynchronizedIntObjectMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TLongObjectMap m = TCollections.synchronizedMap( new TLongObjectHashMap() );
+     *      ...
+     *  TLongSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TLongIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TLongObjectMap synchronizedMap( TLongObjectMap m ) { + return new TSynchronizedLongObjectMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TByteObjectMap m = TCollections.synchronizedMap( new TByteObjectHashMap() );
+     *      ...
+     *  TByteSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TByteIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TByteObjectMap synchronizedMap( TByteObjectMap m ) { + return new TSynchronizedByteObjectMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TShortObjectMap m = TCollections.synchronizedMap( new TShortObjectHashMap() );
+     *      ...
+     *  TShortSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TShortIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TShortObjectMap synchronizedMap( TShortObjectMap m ) { + return new TSynchronizedShortObjectMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TCharObjectMap m = TCollections.synchronizedMap( new TCharObjectHashMap() );
+     *      ...
+     *  TCharSet s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      TCharIterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TCharObjectMap synchronizedMap( TCharObjectMap m ) { + return new TSynchronizedCharObjectMap( m ); + } + + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TObjectDoubleMap m = TCollections.synchronizedMap( new TObjectDoubleHashMap() );
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TObjectDoubleMap synchronizedMap( TObjectDoubleMap m ) { + return new TSynchronizedObjectDoubleMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TObjectFloatMap m = TCollections.synchronizedMap( new TObjectFloatHashMap() );
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TObjectFloatMap synchronizedMap( TObjectFloatMap m ) { + return new TSynchronizedObjectFloatMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TObjectIntMap m = TCollections.synchronizedMap( new TObjectIntHashMap() );
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TObjectIntMap synchronizedMap( TObjectIntMap m ) { + return new TSynchronizedObjectIntMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TObjectLongMap m = TCollections.synchronizedMap( new TObjectLongHashMap() );
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TObjectLongMap synchronizedMap( TObjectLongMap m ) { + return new TSynchronizedObjectLongMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TObjectByteMap m = TCollections.synchronizedMap( new TObjectByteHashMap() );
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TObjectByteMap synchronizedMap( TObjectByteMap m ) { + return new TSynchronizedObjectByteMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TObjectShortMap m = TCollections.synchronizedMap( new TObjectShortHashMap() );
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TObjectShortMap synchronizedMap( TObjectShortMap m ) { + return new TSynchronizedObjectShortMap( m ); + } + + /** + * Returns a synchronized (thread-safe) Trove map backed by the specified + * map. In order to guarantee serial access, it is critical that + * all access to the backing map is accomplished + * through the returned map.

+ * + * It is imperative that the user manually synchronize on the returned + * map when iterating over any of its collection views: + *

+     *  TObjectCharMap m = TCollections.synchronizedMap( new TObjectCharHashMap() );
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized( m ) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while ( i.hasNext() )
+     *          foo( i.next() );
+     *  }
+     * 
+ * Failure to follow this advice may result in non-deterministic behavior. + * + *

The returned map will be serializable if the specified map is + * serializable. + * + * @param m the map to be "wrapped" in a synchronized map. + * @return a synchronized view of the specified map. + */ + public static TObjectCharMap synchronizedMap( TObjectCharMap m ) { + return new TSynchronizedObjectCharMap( m ); + } +} \ No newline at end of file diff --git a/src/gnu/trove/TDecorators.java b/src/gnu/trove/TDecorators.java new file mode 100644 index 0000000..a0f50db --- /dev/null +++ b/src/gnu/trove/TDecorators.java @@ -0,0 +1,896 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove; + + +import java.util.*; + +import gnu.trove.list.*; +import gnu.trove.map.*; +import gnu.trove.set.*; +import gnu.trove.decorator.*; + + + +/** + * This is a static utility class that provides functions for simplifying creation of + * decorators. + * + * @author Robert D. Eden + * @author Jeff Randall + * @since Trove 2.1 + */ +public class TDecorators { + // Hide the constructor + private TDecorators() {} + + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleDoubleMap map ) { + return new TDoubleDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleFloatMap map ) { + return new TDoubleFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleIntMap map ) { + return new TDoubleIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleLongMap map ) { + return new TDoubleLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleByteMap map ) { + return new TDoubleByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleShortMap map ) { + return new TDoubleShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleCharMap map ) { + return new TDoubleCharMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatDoubleMap map ) { + return new TFloatDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatFloatMap map ) { + return new TFloatFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatIntMap map ) { + return new TFloatIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatLongMap map ) { + return new TFloatLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatByteMap map ) { + return new TFloatByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatShortMap map ) { + return new TFloatShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatCharMap map ) { + return new TFloatCharMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntDoubleMap map ) { + return new TIntDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntFloatMap map ) { + return new TIntFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntIntMap map ) { + return new TIntIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntLongMap map ) { + return new TIntLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntByteMap map ) { + return new TIntByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntShortMap map ) { + return new TIntShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntCharMap map ) { + return new TIntCharMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongDoubleMap map ) { + return new TLongDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongFloatMap map ) { + return new TLongFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongIntMap map ) { + return new TLongIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongLongMap map ) { + return new TLongLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongByteMap map ) { + return new TLongByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongShortMap map ) { + return new TLongShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongCharMap map ) { + return new TLongCharMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteDoubleMap map ) { + return new TByteDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteFloatMap map ) { + return new TByteFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteIntMap map ) { + return new TByteIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteLongMap map ) { + return new TByteLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteByteMap map ) { + return new TByteByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteShortMap map ) { + return new TByteShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteCharMap map ) { + return new TByteCharMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortDoubleMap map ) { + return new TShortDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortFloatMap map ) { + return new TShortFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortIntMap map ) { + return new TShortIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortLongMap map ) { + return new TShortLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortByteMap map ) { + return new TShortByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortShortMap map ) { + return new TShortShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortCharMap map ) { + return new TShortCharMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharDoubleMap map ) { + return new TCharDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharFloatMap map ) { + return new TCharFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharIntMap map ) { + return new TCharIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharLongMap map ) { + return new TCharLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharByteMap map ) { + return new TCharByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharShortMap map ) { + return new TCharShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharCharMap map ) { + return new TCharCharMapDecorator( map ); + } + + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TObjectDoubleMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TObjectDoubleMap map ) { + return new TObjectDoubleMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TObjectFloatMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TObjectFloatMap map ) { + return new TObjectFloatMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TObjectIntMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TObjectIntMap map ) { + return new TObjectIntMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TObjectLongMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TObjectLongMap map ) { + return new TObjectLongMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TObjectByteMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TObjectByteMap map ) { + return new TObjectByteMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TObjectShortMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TObjectShortMap map ) { + return new TObjectShortMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TObjectCharMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TObjectCharMap map ) { + return new TObjectCharMapDecorator( map ); + } + + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TDoubleObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TDoubleObjectMap map ) { + return new TDoubleObjectMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TFloatObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TFloatObjectMap map ) { + return new TFloatObjectMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TIntObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TIntObjectMap map ) { + return new TIntObjectMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TLongObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TLongObjectMap map ) { + return new TLongObjectMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TByteObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TByteObjectMap map ) { + return new TByteObjectMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TShortObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TShortObjectMap map ) { + return new TShortObjectMapDecorator( map ); + } + + /** + * Wrap the given map in a decorator that uses the standard {@link java.util.Map Map} + * interface. + * + * @param map the TCharObjectMap to be wrapped + * @return the wrapped map. + */ + public static Map wrap( TCharObjectMap map ) { + return new TCharObjectMapDecorator( map ); + } + + + /** + * Wrap the given set in a decorator that uses the standard {@link java.util.Set Set} + * interface. + * + * @param set the TDoubleSet to be wrapped + * @return the wrapped set. + */ + public static Set wrap( TDoubleSet set ) { + return new TDoubleSetDecorator( set ); + } + + /** + * Wrap the given set in a decorator that uses the standard {@link java.util.Set Set} + * interface. + * + * @param set the TFloatSet to be wrapped + * @return the wrapped set. + */ + public static Set wrap( TFloatSet set ) { + return new TFloatSetDecorator( set ); + } + + /** + * Wrap the given set in a decorator that uses the standard {@link java.util.Set Set} + * interface. + * + * @param set the TIntSet to be wrapped + * @return the wrapped set. + */ + public static Set wrap( TIntSet set ) { + return new TIntSetDecorator( set ); + } + + /** + * Wrap the given set in a decorator that uses the standard {@link java.util.Set Set} + * interface. + * + * @param set the TLongSet to be wrapped + * @return the wrapped set. + */ + public static Set wrap( TLongSet set ) { + return new TLongSetDecorator( set ); + } + + /** + * Wrap the given set in a decorator that uses the standard {@link java.util.Set Set} + * interface. + * + * @param set the TByteSet to be wrapped + * @return the wrapped set. + */ + public static Set wrap( TByteSet set ) { + return new TByteSetDecorator( set ); + } + + /** + * Wrap the given set in a decorator that uses the standard {@link java.util.Set Set} + * interface. + * + * @param set the TShortSet to be wrapped + * @return the wrapped set. + */ + public static Set wrap( TShortSet set ) { + return new TShortSetDecorator( set ); + } + + /** + * Wrap the given set in a decorator that uses the standard {@link java.util.Set Set} + * interface. + * + * @param set the TCharSet to be wrapped + * @return the wrapped set. + */ + public static Set wrap( TCharSet set ) { + return new TCharSetDecorator( set ); + } + + + /** + * Wrap the given list in a decorator that uses the standard {@link java.util.List List} + * interface. + * + * @param list the TDoubleList to be wrapped + * @return the wrapped list. + */ + public static List wrap( TDoubleList list ) { + return new TDoubleListDecorator( list ); + } + + /** + * Wrap the given list in a decorator that uses the standard {@link java.util.List List} + * interface. + * + * @param list the TFloatList to be wrapped + * @return the wrapped list. + */ + public static List wrap( TFloatList list ) { + return new TFloatListDecorator( list ); + } + + /** + * Wrap the given list in a decorator that uses the standard {@link java.util.List List} + * interface. + * + * @param list the TIntList to be wrapped + * @return the wrapped list. + */ + public static List wrap( TIntList list ) { + return new TIntListDecorator( list ); + } + + /** + * Wrap the given list in a decorator that uses the standard {@link java.util.List List} + * interface. + * + * @param list the TLongList to be wrapped + * @return the wrapped list. + */ + public static List wrap( TLongList list ) { + return new TLongListDecorator( list ); + } + + /** + * Wrap the given list in a decorator that uses the standard {@link java.util.List List} + * interface. + * + * @param list the TByteList to be wrapped + * @return the wrapped list. + */ + public static List wrap( TByteList list ) { + return new TByteListDecorator( list ); + } + + /** + * Wrap the given list in a decorator that uses the standard {@link java.util.List List} + * interface. + * + * @param list the TShortList to be wrapped + * @return the wrapped list. + */ + public static List wrap( TShortList list ) { + return new TShortListDecorator( list ); + } + + /** + * Wrap the given list in a decorator that uses the standard {@link java.util.List List} + * interface. + * + * @param list the TCharList to be wrapped + * @return the wrapped list. + */ + public static List wrap( TCharList list ) { + return new TCharListDecorator( list ); + } +} \ No newline at end of file diff --git a/src/gnu/trove/TDoubleCollection.java b/src/gnu/trove/TDoubleCollection.java new file mode 100644 index 0000000..7edf5f9 --- /dev/null +++ b/src/gnu/trove/TDoubleCollection.java @@ -0,0 +1,316 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +import java.util.Collection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.procedure.TDoubleProcedure; + +/** + * An interface that mimics the Collection interface. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $ + */ + +public interface TDoubleCollection { + static final long serialVersionUID = 1L; + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + double getNoEntryValue(); + + + /** + * Returns the number of elements in this collection (its cardinality). If this + * collection contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection (its cardinality) + */ + int size(); + + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this collection contains the specified element. + * + * @param entry an double value + * @return true if the collection contains the specified element. + */ + boolean contains( double entry ); + + + /** + * Creates an iterator over the values of the collection. The iterator + * supports element deletion. + * + * @return an TDoubleIterator value + */ + TDoubleIterator iterator(); + + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this collection + */ + double[] toArray(); + + + /** + * Returns an array containing elements in this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element in + * the array immediately following the end of the collection is collection to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this collection only if the caller knows that this + * collection does not contain any elements representing null.) + * + *

If the native array is smaller than the collection size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this collection are to be + * stored. + * @return an double[] containing all the elements in this collection + * @throws NullPointerException if the specified array is null + */ + double[] toArray( double[] dest ); + + + /** + * Inserts a value into the collection. + * + * @param entry a double value + * @return true if the collection was modified by the add operation + */ + boolean add( double entry ); + + + /** + * Removes entry from the collection. + * + * @param entry an double value + * @return true if the collection was modified by the remove operation. + */ + boolean remove( double entry ); + + + /** + * Tests the collection to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * TDoubleCollection are present. + * + * @param collection a TDoubleCollection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( TDoubleCollection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * array are present. + * + * @param array as array of double primitives. + * @return true if all elements were present in the collection. + */ + boolean containsAll( double[] array ); + + + /** + * Adds all of the elements in collection to the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TDoubleCollection to the collection. + * + * @param collection a TDoubleCollection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( TDoubleCollection collection ); + + + /** + * Adds all of the elements in the array to the collection. + * + * @param array a array of double primitives. + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( double[] array ); + + + /** + * Removes any values in the collection which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the collection which are not contained in + * TDoubleCollection. + * + * @param collection a TDoubleCollection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( TDoubleCollection collection ); + + + /** + * Removes any values in the collection which are not contained in + * array. + * + * @param array an array of double primitives. + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( double[] array ); + + + /** + * Removes all of the elements in collection from the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TDoubleCollection from the collection. + * + * @param collection a TDoubleCollection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( TDoubleCollection collection ); + + + /** + * Removes all of the elements in array from the collection. + * + * @param array an array of double primitives. + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( double[] array ); + + + /** + * Empties the collection. + */ + void clear(); + + + /** + * Executes procedure for each element in the collection. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the collection terminated because + * the procedure returned false for some value. + */ + boolean forEach( TDoubleProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality. Returns + * true if the specified object is also a collection, the two collection + * have the same size, and every member of the specified collection is + * contained in this collection (or equivalently, every member of this collection is + * contained in the specified collection). This definition ensures that the + * equals method works properly across different implementations of the + * collection interface. + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this collection + */ + boolean equals( Object o ); + + + /** + * Returns the hash code value for this collection. The hash code of a collection is + * defined to be the sum of the hash codes of the elements in the collection. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two collection s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this collection + * @see Object#equals(Object) + * @see Collection#equals(Object) + */ + int hashCode(); + + +} // TDoubleCollection diff --git a/src/gnu/trove/TFloatCollection.java b/src/gnu/trove/TFloatCollection.java new file mode 100644 index 0000000..6b610c5 --- /dev/null +++ b/src/gnu/trove/TFloatCollection.java @@ -0,0 +1,316 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +import java.util.Collection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.procedure.TFloatProcedure; + +/** + * An interface that mimics the Collection interface. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $ + */ + +public interface TFloatCollection { + static final long serialVersionUID = 1L; + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + float getNoEntryValue(); + + + /** + * Returns the number of elements in this collection (its cardinality). If this + * collection contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection (its cardinality) + */ + int size(); + + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this collection contains the specified element. + * + * @param entry an float value + * @return true if the collection contains the specified element. + */ + boolean contains( float entry ); + + + /** + * Creates an iterator over the values of the collection. The iterator + * supports element deletion. + * + * @return an TFloatIterator value + */ + TFloatIterator iterator(); + + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this collection + */ + float[] toArray(); + + + /** + * Returns an array containing elements in this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element in + * the array immediately following the end of the collection is collection to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this collection only if the caller knows that this + * collection does not contain any elements representing null.) + * + *

If the native array is smaller than the collection size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this collection are to be + * stored. + * @return an float[] containing all the elements in this collection + * @throws NullPointerException if the specified array is null + */ + float[] toArray( float[] dest ); + + + /** + * Inserts a value into the collection. + * + * @param entry a float value + * @return true if the collection was modified by the add operation + */ + boolean add( float entry ); + + + /** + * Removes entry from the collection. + * + * @param entry an float value + * @return true if the collection was modified by the remove operation. + */ + boolean remove( float entry ); + + + /** + * Tests the collection to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * TFloatCollection are present. + * + * @param collection a TFloatCollection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( TFloatCollection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * array are present. + * + * @param array as array of float primitives. + * @return true if all elements were present in the collection. + */ + boolean containsAll( float[] array ); + + + /** + * Adds all of the elements in collection to the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TFloatCollection to the collection. + * + * @param collection a TFloatCollection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( TFloatCollection collection ); + + + /** + * Adds all of the elements in the array to the collection. + * + * @param array a array of float primitives. + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( float[] array ); + + + /** + * Removes any values in the collection which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the collection which are not contained in + * TFloatCollection. + * + * @param collection a TFloatCollection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( TFloatCollection collection ); + + + /** + * Removes any values in the collection which are not contained in + * array. + * + * @param array an array of float primitives. + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( float[] array ); + + + /** + * Removes all of the elements in collection from the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TFloatCollection from the collection. + * + * @param collection a TFloatCollection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( TFloatCollection collection ); + + + /** + * Removes all of the elements in array from the collection. + * + * @param array an array of float primitives. + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( float[] array ); + + + /** + * Empties the collection. + */ + void clear(); + + + /** + * Executes procedure for each element in the collection. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the collection terminated because + * the procedure returned false for some value. + */ + boolean forEach( TFloatProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality. Returns + * true if the specified object is also a collection, the two collection + * have the same size, and every member of the specified collection is + * contained in this collection (or equivalently, every member of this collection is + * contained in the specified collection). This definition ensures that the + * equals method works properly across different implementations of the + * collection interface. + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this collection + */ + boolean equals( Object o ); + + + /** + * Returns the hash code value for this collection. The hash code of a collection is + * defined to be the sum of the hash codes of the elements in the collection. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two collection s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this collection + * @see Object#equals(Object) + * @see Collection#equals(Object) + */ + int hashCode(); + + +} // TFloatCollection diff --git a/src/gnu/trove/TIntCollection.java b/src/gnu/trove/TIntCollection.java new file mode 100644 index 0000000..86716e7 --- /dev/null +++ b/src/gnu/trove/TIntCollection.java @@ -0,0 +1,316 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +import java.util.Collection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TIntIterator; +import gnu.trove.procedure.TIntProcedure; + +/** + * An interface that mimics the Collection interface. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $ + */ + +public interface TIntCollection { + static final long serialVersionUID = 1L; + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + int getNoEntryValue(); + + + /** + * Returns the number of elements in this collection (its cardinality). If this + * collection contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection (its cardinality) + */ + int size(); + + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this collection contains the specified element. + * + * @param entry an int value + * @return true if the collection contains the specified element. + */ + boolean contains( int entry ); + + + /** + * Creates an iterator over the values of the collection. The iterator + * supports element deletion. + * + * @return an TIntIterator value + */ + TIntIterator iterator(); + + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this collection + */ + int[] toArray(); + + + /** + * Returns an array containing elements in this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element in + * the array immediately following the end of the collection is collection to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this collection only if the caller knows that this + * collection does not contain any elements representing null.) + * + *

If the native array is smaller than the collection size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this collection are to be + * stored. + * @return an int[] containing all the elements in this collection + * @throws NullPointerException if the specified array is null + */ + int[] toArray( int[] dest ); + + + /** + * Inserts a value into the collection. + * + * @param entry a int value + * @return true if the collection was modified by the add operation + */ + boolean add( int entry ); + + + /** + * Removes entry from the collection. + * + * @param entry an int value + * @return true if the collection was modified by the remove operation. + */ + boolean remove( int entry ); + + + /** + * Tests the collection to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * TIntCollection are present. + * + * @param collection a TIntCollection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( TIntCollection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * array are present. + * + * @param array as array of int primitives. + * @return true if all elements were present in the collection. + */ + boolean containsAll( int[] array ); + + + /** + * Adds all of the elements in collection to the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TIntCollection to the collection. + * + * @param collection a TIntCollection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( TIntCollection collection ); + + + /** + * Adds all of the elements in the array to the collection. + * + * @param array a array of int primitives. + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( int[] array ); + + + /** + * Removes any values in the collection which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the collection which are not contained in + * TIntCollection. + * + * @param collection a TIntCollection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( TIntCollection collection ); + + + /** + * Removes any values in the collection which are not contained in + * array. + * + * @param array an array of int primitives. + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( int[] array ); + + + /** + * Removes all of the elements in collection from the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TIntCollection from the collection. + * + * @param collection a TIntCollection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( TIntCollection collection ); + + + /** + * Removes all of the elements in array from the collection. + * + * @param array an array of int primitives. + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( int[] array ); + + + /** + * Empties the collection. + */ + void clear(); + + + /** + * Executes procedure for each element in the collection. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the collection terminated because + * the procedure returned false for some value. + */ + boolean forEach( TIntProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality. Returns + * true if the specified object is also a collection, the two collection + * have the same size, and every member of the specified collection is + * contained in this collection (or equivalently, every member of this collection is + * contained in the specified collection). This definition ensures that the + * equals method works properly across different implementations of the + * collection interface. + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this collection + */ + boolean equals( Object o ); + + + /** + * Returns the hash code value for this collection. The hash code of a collection is + * defined to be the sum of the hash codes of the elements in the collection. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two collection s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this collection + * @see Object#equals(Object) + * @see Collection#equals(Object) + */ + int hashCode(); + + +} // TIntCollection diff --git a/src/gnu/trove/TLongCollection.java b/src/gnu/trove/TLongCollection.java new file mode 100644 index 0000000..f8ae556 --- /dev/null +++ b/src/gnu/trove/TLongCollection.java @@ -0,0 +1,316 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +import java.util.Collection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TLongIterator; +import gnu.trove.procedure.TLongProcedure; + +/** + * An interface that mimics the Collection interface. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $ + */ + +public interface TLongCollection { + static final long serialVersionUID = 1L; + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + long getNoEntryValue(); + + + /** + * Returns the number of elements in this collection (its cardinality). If this + * collection contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection (its cardinality) + */ + int size(); + + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this collection contains the specified element. + * + * @param entry an long value + * @return true if the collection contains the specified element. + */ + boolean contains( long entry ); + + + /** + * Creates an iterator over the values of the collection. The iterator + * supports element deletion. + * + * @return an TLongIterator value + */ + TLongIterator iterator(); + + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this collection + */ + long[] toArray(); + + + /** + * Returns an array containing elements in this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element in + * the array immediately following the end of the collection is collection to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this collection only if the caller knows that this + * collection does not contain any elements representing null.) + * + *

If the native array is smaller than the collection size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this collection are to be + * stored. + * @return an long[] containing all the elements in this collection + * @throws NullPointerException if the specified array is null + */ + long[] toArray( long[] dest ); + + + /** + * Inserts a value into the collection. + * + * @param entry a long value + * @return true if the collection was modified by the add operation + */ + boolean add( long entry ); + + + /** + * Removes entry from the collection. + * + * @param entry an long value + * @return true if the collection was modified by the remove operation. + */ + boolean remove( long entry ); + + + /** + * Tests the collection to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * TLongCollection are present. + * + * @param collection a TLongCollection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( TLongCollection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * array are present. + * + * @param array as array of long primitives. + * @return true if all elements were present in the collection. + */ + boolean containsAll( long[] array ); + + + /** + * Adds all of the elements in collection to the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TLongCollection to the collection. + * + * @param collection a TLongCollection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( TLongCollection collection ); + + + /** + * Adds all of the elements in the array to the collection. + * + * @param array a array of long primitives. + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( long[] array ); + + + /** + * Removes any values in the collection which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the collection which are not contained in + * TLongCollection. + * + * @param collection a TLongCollection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( TLongCollection collection ); + + + /** + * Removes any values in the collection which are not contained in + * array. + * + * @param array an array of long primitives. + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( long[] array ); + + + /** + * Removes all of the elements in collection from the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TLongCollection from the collection. + * + * @param collection a TLongCollection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( TLongCollection collection ); + + + /** + * Removes all of the elements in array from the collection. + * + * @param array an array of long primitives. + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( long[] array ); + + + /** + * Empties the collection. + */ + void clear(); + + + /** + * Executes procedure for each element in the collection. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the collection terminated because + * the procedure returned false for some value. + */ + boolean forEach( TLongProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality. Returns + * true if the specified object is also a collection, the two collection + * have the same size, and every member of the specified collection is + * contained in this collection (or equivalently, every member of this collection is + * contained in the specified collection). This definition ensures that the + * equals method works properly across different implementations of the + * collection interface. + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this collection + */ + boolean equals( Object o ); + + + /** + * Returns the hash code value for this collection. The hash code of a collection is + * defined to be the sum of the hash codes of the elements in the collection. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two collection s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this collection + * @see Object#equals(Object) + * @see Collection#equals(Object) + */ + int hashCode(); + + +} // TLongCollection diff --git a/src/gnu/trove/TShortCollection.java b/src/gnu/trove/TShortCollection.java new file mode 100644 index 0000000..c66a349 --- /dev/null +++ b/src/gnu/trove/TShortCollection.java @@ -0,0 +1,316 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + + +import java.util.Collection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TShortIterator; +import gnu.trove.procedure.TShortProcedure; + +/** + * An interface that mimics the Collection interface. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $ + */ + +public interface TShortCollection { + static final long serialVersionUID = 1L; + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + short getNoEntryValue(); + + + /** + * Returns the number of elements in this collection (its cardinality). If this + * collection contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection (its cardinality) + */ + int size(); + + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this collection contains the specified element. + * + * @param entry an short value + * @return true if the collection contains the specified element. + */ + boolean contains( short entry ); + + + /** + * Creates an iterator over the values of the collection. The iterator + * supports element deletion. + * + * @return an TShortIterator value + */ + TShortIterator iterator(); + + + /** + * Returns an array containing all of the elements in this collection. + * If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this collection. (In other words, this method must + * allocate a new array even if this collection is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this collection + */ + short[] toArray(); + + + /** + * Returns an array containing elements in this collection. + * + *

If this collection fits in the specified array with room to spare + * (i.e., the array has more elements than this collection), the element in + * the array immediately following the end of the collection is collection to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this collection only if the caller knows that this + * collection does not contain any elements representing null.) + * + *

If the native array is smaller than the collection size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this collection makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this collection are to be + * stored. + * @return an short[] containing all the elements in this collection + * @throws NullPointerException if the specified array is null + */ + short[] toArray( short[] dest ); + + + /** + * Inserts a value into the collection. + * + * @param entry a short value + * @return true if the collection was modified by the add operation + */ + boolean add( short entry ); + + + /** + * Removes entry from the collection. + * + * @param entry an short value + * @return true if the collection was modified by the remove operation. + */ + boolean remove( short entry ); + + + /** + * Tests the collection to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * TShortCollection are present. + * + * @param collection a TShortCollection value + * @return true if all elements were present in the collection. + */ + boolean containsAll( TShortCollection collection ); + + + /** + * Tests the collection to determine if all of the elements in + * array are present. + * + * @param array as array of short primitives. + * @return true if all elements were present in the collection. + */ + boolean containsAll( short[] array ); + + + /** + * Adds all of the elements in collection to the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TShortCollection to the collection. + * + * @param collection a TShortCollection value + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( TShortCollection collection ); + + + /** + * Adds all of the elements in the array to the collection. + * + * @param array a array of short primitives. + * @return true if the collection was modified by the add all operation. + */ + boolean addAll( short[] array ); + + + /** + * Removes any values in the collection which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the collection which are not contained in + * TShortCollection. + * + * @param collection a TShortCollection value + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( TShortCollection collection ); + + + /** + * Removes any values in the collection which are not contained in + * array. + * + * @param array an array of short primitives. + * @return true if the collection was modified by the retain all operation + */ + boolean retainAll( short[] array ); + + + /** + * Removes all of the elements in collection from the collection. + * + * @param collection a Collection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TShortCollection from the collection. + * + * @param collection a TShortCollection value + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( TShortCollection collection ); + + + /** + * Removes all of the elements in array from the collection. + * + * @param array an array of short primitives. + * @return true if the collection was modified by the remove all operation. + */ + boolean removeAll( short[] array ); + + + /** + * Empties the collection. + */ + void clear(); + + + /** + * Executes procedure for each element in the collection. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the collection terminated because + * the procedure returned false for some value. + */ + boolean forEach( TShortProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this collection for equality. Returns + * true if the specified object is also a collection, the two collection + * have the same size, and every member of the specified collection is + * contained in this collection (or equivalently, every member of this collection is + * contained in the specified collection). This definition ensures that the + * equals method works properly across different implementations of the + * collection interface. + * + * @param o object to be compared for equality with this collection + * @return true if the specified object is equal to this collection + */ + boolean equals( Object o ); + + + /** + * Returns the hash code value for this collection. The hash code of a collection is + * defined to be the sum of the hash codes of the elements in the collection. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two collection s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + * @return the hash code value for this collection + * @see Object#equals(Object) + * @see Collection#equals(Object) + */ + int hashCode(); + + +} // TShortCollection diff --git a/src/gnu/trove/Version.java b/src/gnu/trove/Version.java new file mode 100644 index 0000000..7bf94c4 --- /dev/null +++ b/src/gnu/trove/Version.java @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove; + +/** + * Simple class meant as a possible main class (via manifest) to report the + * implementation version of the trove4j jar. + *

+ * This may be useful to ask feedback WITH build version information + *

+ * The Main-Class entry in the manifest.mf should be set during the build as well + * as the Implementation-Version manifest attribute should be set as well. + *

+ * Created by IntelliJ IDEA. + * User: Johan Parent + * Date: 3/03/11 + * Time: 22:10 + */ +public class Version { + public static void main(String[] args) { + System.out.println(getVersion()); + } + + /** + * Returns the implementation version of trove4j. Intended for applications + * wanting to return the version of trove4j they are using + *

+ * NOTE: this method will only return a useful version when working + * with a trove4j jar as it requires a manifest file + * + * @return + */ + public static String getVersion() { + String version = Version.class.getPackage().getImplementationVersion(); + // + if (version != null) { + return "trove4j version " + version; + } + + return "Sorry no Implementation-Version manifest attribute available"; + } +} diff --git a/src/gnu/trove/decorator/TByteByteMapDecorator.java b/src/gnu/trove/decorator/TByteByteMapDecorator.java new file mode 100644 index 0000000..830651b --- /dev/null +++ b/src/gnu/trove/decorator/TByteByteMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteByteMap; +import gnu.trove.iterator.TByteByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteByteMap to wrap. + */ + public TByteByteMapDecorator( TByteByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteByteMap instance. + */ + public TByteByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Byte(0) if none was found. + */ + public Byte put( Byte key, Byte value ) { + byte k; + byte v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + byte retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Byte remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteByteMapDecorator.this.containsKey(k) + && TByteByteMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte ik = it.key(); + final Byte key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + byte iv = it.value(); + final Byte v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Byte getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Object key ) { + return ( ( Byte ) key ).byteValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TByteByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TByteByteHashMapDecorator diff --git a/src/gnu/trove/decorator/TByteCharMapDecorator.java b/src/gnu/trove/decorator/TByteCharMapDecorator.java new file mode 100644 index 0000000..87bd86c --- /dev/null +++ b/src/gnu/trove/decorator/TByteCharMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteCharMap; +import gnu.trove.iterator.TByteCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteCharMap to wrap. + */ + public TByteCharMapDecorator( TByteCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteCharMap instance. + */ + public TByteCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Character(0) if none was found. + */ + public Character put( Byte key, Character value ) { + byte k; + char v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + char retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Character remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteCharMapDecorator.this.containsKey(k) + && TByteCharMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte ik = it.key(); + final Byte key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + char iv = it.value(); + final Character v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Byte getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Object key ) { + return ( ( Byte ) key ).byteValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TByteCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TByteCharHashMapDecorator diff --git a/src/gnu/trove/decorator/TByteDoubleMapDecorator.java b/src/gnu/trove/decorator/TByteDoubleMapDecorator.java new file mode 100644 index 0000000..e0efb1d --- /dev/null +++ b/src/gnu/trove/decorator/TByteDoubleMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteDoubleMap; +import gnu.trove.iterator.TByteDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteDoubleMap to wrap. + */ + public TByteDoubleMapDecorator( TByteDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteDoubleMap instance. + */ + public TByteDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Double(0) if none was found. + */ + public Double put( Byte key, Double value ) { + byte k; + double v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + double retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Double remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteDoubleMapDecorator.this.containsKey(k) + && TByteDoubleMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte ik = it.key(); + final Byte key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + double iv = it.value(); + final Double v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Byte getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Object key ) { + return ( ( Byte ) key ).byteValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TByteDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TByteDoubleHashMapDecorator diff --git a/src/gnu/trove/decorator/TByteFloatMapDecorator.java b/src/gnu/trove/decorator/TByteFloatMapDecorator.java new file mode 100644 index 0000000..2b75c37 --- /dev/null +++ b/src/gnu/trove/decorator/TByteFloatMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteFloatMap; +import gnu.trove.iterator.TByteFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteFloatMap to wrap. + */ + public TByteFloatMapDecorator( TByteFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteFloatMap instance. + */ + public TByteFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Float(0) if none was found. + */ + public Float put( Byte key, Float value ) { + byte k; + float v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + float retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Float remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteFloatMapDecorator.this.containsKey(k) + && TByteFloatMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte ik = it.key(); + final Byte key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + float iv = it.value(); + final Float v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Byte getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Object key ) { + return ( ( Byte ) key ).byteValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TByteFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TByteFloatHashMapDecorator diff --git a/src/gnu/trove/decorator/TByteIntMapDecorator.java b/src/gnu/trove/decorator/TByteIntMapDecorator.java new file mode 100644 index 0000000..23e0c7d --- /dev/null +++ b/src/gnu/trove/decorator/TByteIntMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteIntMap; +import gnu.trove.iterator.TByteIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteIntMap to wrap. + */ + public TByteIntMapDecorator( TByteIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteIntMap instance. + */ + public TByteIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( Byte key, Integer value ) { + byte k; + int v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + int retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Integer remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteIntMapDecorator.this.containsKey(k) + && TByteIntMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte ik = it.key(); + final Byte key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + int iv = it.value(); + final Integer v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Byte getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Object key ) { + return ( ( Byte ) key ).byteValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TByteIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TByteIntHashMapDecorator diff --git a/src/gnu/trove/decorator/TByteListDecorator.java b/src/gnu/trove/decorator/TByteListDecorator.java new file mode 100644 index 0000000..e5061cb --- /dev/null +++ b/src/gnu/trove/decorator/TByteListDecorator.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.list.TByteList; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractList; +import java.util.List; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteList conform to the java.util.List API. + * This class simply decorates an underlying TByteList and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * + * @author Robert D. Eden + */ +public class TByteListDecorator extends AbstractList + implements List, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive list */ + protected TByteList list; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteListDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param list the TByteList to wrap. + */ + public TByteListDecorator( TByteList list ) { + super(); + this.list = list; + } + + + /** + * Returns a reference to the list wrapped by this decorator. + * + * @return the wrapped TByteList instance. + */ + public TByteList getList() { + return list; + } + + + @Override + public int size() { + return list.size(); + } + + + @Override + public Byte get( int index ) { + byte value = list.get( index ); + if ( value == list.getNoEntryValue() ) return null; + else return Byte.valueOf( value ); + } + + + @Override + public Byte set( int index, Byte value ) { + byte previous_value = list.set( index, value ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Byte.valueOf( previous_value ); + } + + + @Override + public void add( int index, Byte value ) { + list.insert( index, value.byteValue() ); + } + + + @Override + public Byte remove( int index ) { + byte previous_value = list.removeAt( index ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Byte.valueOf( previous_value ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + list = ( TByteList ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // LIST + out.writeObject( list ); + } + +} diff --git a/src/gnu/trove/decorator/TByteLongMapDecorator.java b/src/gnu/trove/decorator/TByteLongMapDecorator.java new file mode 100644 index 0000000..ba29ddf --- /dev/null +++ b/src/gnu/trove/decorator/TByteLongMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteLongMap; +import gnu.trove.iterator.TByteLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteLongMap to wrap. + */ + public TByteLongMapDecorator( TByteLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteLongMap instance. + */ + public TByteLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Long(0) if none was found. + */ + public Long put( Byte key, Long value ) { + byte k; + long v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + long retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Long remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteLongMapDecorator.this.containsKey(k) + && TByteLongMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte ik = it.key(); + final Byte key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + long iv = it.value(); + final Long v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Byte getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Object key ) { + return ( ( Byte ) key ).byteValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TByteLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TByteLongHashMapDecorator diff --git a/src/gnu/trove/decorator/TByteObjectMapDecorator.java b/src/gnu/trove/decorator/TByteObjectMapDecorator.java new file mode 100644 index 0000000..ad676ce --- /dev/null +++ b/src/gnu/trove/decorator/TByteObjectMapDecorator.java @@ -0,0 +1,361 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteObjectMap; +import gnu.trove.iterator.TByteObjectIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteObjectMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteObjectMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteObjectMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteObjectMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteObjectMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteObjectMap to wrap. + */ + public TByteObjectMapDecorator( TByteObjectMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteObjectMap instance. + */ + public TByteObjectMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Byte value + * @param value an Object value + * @return the previous value associated with key, + * or null if none was found. + */ + public V put( Byte key, V value ) { + byte k; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + return _map.put( k, value ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public V get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( ( Byte ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.get( k ); + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public V remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( ( Byte ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.remove( k ); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteObjectMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteObjectMapDecorator.this.containsKey( k ) && + TByteObjectMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteObjectIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte k = it.key(); + final Byte key = (k == _map.getNoEntryKey()) ? null : wrapKey( k ); + final V v = it.value(); + return new Map.Entry() { + private V val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals( key ) + && ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public Byte getKey() { + return key; + } + + public V getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public V setValue( V value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteObjectMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return _map.containsValue( val ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( ( ( Byte ) key ).byteValue() ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Byte key ) { + return key.byteValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TByteObjectMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TByteObjectHashMapDecorator diff --git a/src/gnu/trove/decorator/TByteSetDecorator.java b/src/gnu/trove/decorator/TByteSetDecorator.java new file mode 100644 index 0000000..9c13d43 --- /dev/null +++ b/src/gnu/trove/decorator/TByteSetDecorator.java @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.set.TByteSet; +import gnu.trove.iterator.TByteIterator; + +import java.io.*; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteSet conform to the java.util.Set API. + * This class simply decorates an underlying TByteSet and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ *

+ * Created: Tue Sep 24 22:08:17 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteSetDecorator extends AbstractSet + implements Set, Externalizable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive set */ + protected TByteSet _set; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteSetDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive set. + * + * @param set the TByteSet to wrap. + */ + public TByteSetDecorator( TByteSet set ) { + super(); + this._set = set; + } + + + /** + * Returns a reference to the set wrapped by this decorator. + * + * @return the wrapped TByteSet instance. + */ + public TByteSet getSet() { + return _set; + } + + + /** + * Inserts a value into the set. + * + * @param value true if the set was modified by the insertion + */ + public boolean add( Byte value ) { + return value != null && _set.add( value.byteValue() ); + } + + + /** + * Compares this set with another set for equality of their stored + * entries. + * + * @param other an Object value + * @return true if the sets are identical + */ + public boolean equals( Object other ) { + if ( _set.equals( other ) ) { + return true; // comparing two trove sets + } else if ( other instanceof Set ) { + Set that = ( Set ) other; + if ( that.size() != _set.size() ) { + return false; // different sizes, no need to compare + } else { // now we have to do it the hard way + Iterator it = that.iterator(); + for ( int i = that.size(); i-- > 0; ) { + Object val = it.next(); + if ( val instanceof Byte ) { + byte v = ( ( Byte ) val ).byteValue(); + if ( _set.contains( v ) ) { + // match, ok to continue + } else { + return false; // no match: we're done + } + } else { + return false; // different type in other set + } + } + return true; // all entries match + } + } else { + return false; + } + } + + + /** + * Empties the set. + */ + public void clear() { + this._set.clear(); + } + + + /** + * Deletes a value from the set. + * + * @param value an Object value + * @return true if the set was modified + */ + public boolean remove( Object value ) { + return value instanceof Byte && _set.remove( ( ( Byte ) value ).byteValue() ); + } + + + /** + * Creates an iterator over the values of the set. + * + * @return an iterator with support for removals in the underlying set + */ + public Iterator iterator() { + return new Iterator() { + private final TByteIterator it = _set.iterator(); + + public Byte next() { + return Byte.valueOf( it.next() ); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + + /** + * Returns the number of entries in the set. + * + * @return the set's size. + */ + public int size() { + return this._set.size(); + } + + + /** + * Indicates whether set has any entries. + * + * @return true if the set is empty + */ + public boolean isEmpty() { + return this._set.size() == 0; + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean contains( Object o ) { + if ( ! ( o instanceof Byte ) ) return false; + return _set.contains( ( ( Byte ) o ).byteValue() ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SET + _set = ( TByteSet ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SET + out.writeObject( _set ); + } +} // TByteHashSetDecorator diff --git a/src/gnu/trove/decorator/TByteShortMapDecorator.java b/src/gnu/trove/decorator/TByteShortMapDecorator.java new file mode 100644 index 0000000..44de8f9 --- /dev/null +++ b/src/gnu/trove/decorator/TByteShortMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TByteShortMap; +import gnu.trove.iterator.TByteShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TByteShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TByteShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TByteShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TByteShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TByteShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TByteShortMap to wrap. + */ + public TByteShortMapDecorator( TByteShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TByteShortMap instance. + */ + public TByteShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Short(0) if none was found. + */ + public Short put( Byte key, Short value ) { + byte k; + short v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + short retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Short remove( Object key ) { + byte k; + if ( key != null ) { + if ( key instanceof Byte ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TByteShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TByteShortMapDecorator.this.containsKey(k) + && TByteShortMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TByteShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + byte ik = it.key(); + final Byte key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + short iv = it.value(); + final Short v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Byte getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Byte key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TByteShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Byte && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Byte wrapKey( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected byte unwrapKey( Object key ) { + return ( ( Byte ) key ).byteValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TByteShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TByteShortHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharByteMapDecorator.java b/src/gnu/trove/decorator/TCharByteMapDecorator.java new file mode 100644 index 0000000..0d18037 --- /dev/null +++ b/src/gnu/trove/decorator/TCharByteMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharByteMap; +import gnu.trove.iterator.TCharByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharByteMap to wrap. + */ + public TCharByteMapDecorator( TCharByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharByteMap instance. + */ + public TCharByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Byte(0) if none was found. + */ + public Byte put( Character key, Byte value ) { + char k; + byte v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + byte retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Byte remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharByteMapDecorator.this.containsKey(k) + && TCharByteMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char ik = it.key(); + final Character key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + byte iv = it.value(); + final Byte v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Character getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Object key ) { + return ( ( Character ) key ).charValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TCharByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TCharByteHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharCharMapDecorator.java b/src/gnu/trove/decorator/TCharCharMapDecorator.java new file mode 100644 index 0000000..a1f1a99 --- /dev/null +++ b/src/gnu/trove/decorator/TCharCharMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharCharMap; +import gnu.trove.iterator.TCharCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharCharMap to wrap. + */ + public TCharCharMapDecorator( TCharCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharCharMap instance. + */ + public TCharCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Character(0) if none was found. + */ + public Character put( Character key, Character value ) { + char k; + char v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + char retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Character remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharCharMapDecorator.this.containsKey(k) + && TCharCharMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char ik = it.key(); + final Character key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + char iv = it.value(); + final Character v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Character getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Object key ) { + return ( ( Character ) key ).charValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TCharCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TCharCharHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharDoubleMapDecorator.java b/src/gnu/trove/decorator/TCharDoubleMapDecorator.java new file mode 100644 index 0000000..ac3e96e --- /dev/null +++ b/src/gnu/trove/decorator/TCharDoubleMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharDoubleMap; +import gnu.trove.iterator.TCharDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharDoubleMap to wrap. + */ + public TCharDoubleMapDecorator( TCharDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharDoubleMap instance. + */ + public TCharDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Double(0) if none was found. + */ + public Double put( Character key, Double value ) { + char k; + double v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + double retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Double remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharDoubleMapDecorator.this.containsKey(k) + && TCharDoubleMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char ik = it.key(); + final Character key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + double iv = it.value(); + final Double v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Character getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Object key ) { + return ( ( Character ) key ).charValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TCharDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TCharDoubleHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharFloatMapDecorator.java b/src/gnu/trove/decorator/TCharFloatMapDecorator.java new file mode 100644 index 0000000..a3da504 --- /dev/null +++ b/src/gnu/trove/decorator/TCharFloatMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharFloatMap; +import gnu.trove.iterator.TCharFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharFloatMap to wrap. + */ + public TCharFloatMapDecorator( TCharFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharFloatMap instance. + */ + public TCharFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Float(0) if none was found. + */ + public Float put( Character key, Float value ) { + char k; + float v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + float retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Float remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharFloatMapDecorator.this.containsKey(k) + && TCharFloatMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char ik = it.key(); + final Character key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + float iv = it.value(); + final Float v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Character getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Object key ) { + return ( ( Character ) key ).charValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TCharFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TCharFloatHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharIntMapDecorator.java b/src/gnu/trove/decorator/TCharIntMapDecorator.java new file mode 100644 index 0000000..fcdcb75 --- /dev/null +++ b/src/gnu/trove/decorator/TCharIntMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharIntMap; +import gnu.trove.iterator.TCharIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharIntMap to wrap. + */ + public TCharIntMapDecorator( TCharIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharIntMap instance. + */ + public TCharIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( Character key, Integer value ) { + char k; + int v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + int retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Integer remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharIntMapDecorator.this.containsKey(k) + && TCharIntMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char ik = it.key(); + final Character key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + int iv = it.value(); + final Integer v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Character getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Object key ) { + return ( ( Character ) key ).charValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TCharIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TCharIntHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharListDecorator.java b/src/gnu/trove/decorator/TCharListDecorator.java new file mode 100644 index 0000000..35e49c3 --- /dev/null +++ b/src/gnu/trove/decorator/TCharListDecorator.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.list.TCharList; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractList; +import java.util.List; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharList conform to the java.util.List API. + * This class simply decorates an underlying TCharList and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * + * @author Robert D. Eden + */ +public class TCharListDecorator extends AbstractList + implements List, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive list */ + protected TCharList list; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharListDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param list the TCharList to wrap. + */ + public TCharListDecorator( TCharList list ) { + super(); + this.list = list; + } + + + /** + * Returns a reference to the list wrapped by this decorator. + * + * @return the wrapped TCharList instance. + */ + public TCharList getList() { + return list; + } + + + @Override + public int size() { + return list.size(); + } + + + @Override + public Character get( int index ) { + char value = list.get( index ); + if ( value == list.getNoEntryValue() ) return null; + else return Character.valueOf( value ); + } + + + @Override + public Character set( int index, Character value ) { + char previous_value = list.set( index, value ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Character.valueOf( previous_value ); + } + + + @Override + public void add( int index, Character value ) { + list.insert( index, value.charValue() ); + } + + + @Override + public Character remove( int index ) { + char previous_value = list.removeAt( index ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Character.valueOf( previous_value ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + list = ( TCharList ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // LIST + out.writeObject( list ); + } + +} diff --git a/src/gnu/trove/decorator/TCharLongMapDecorator.java b/src/gnu/trove/decorator/TCharLongMapDecorator.java new file mode 100644 index 0000000..19d1824 --- /dev/null +++ b/src/gnu/trove/decorator/TCharLongMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharLongMap; +import gnu.trove.iterator.TCharLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharLongMap to wrap. + */ + public TCharLongMapDecorator( TCharLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharLongMap instance. + */ + public TCharLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Long(0) if none was found. + */ + public Long put( Character key, Long value ) { + char k; + long v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + long retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Long remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharLongMapDecorator.this.containsKey(k) + && TCharLongMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char ik = it.key(); + final Character key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + long iv = it.value(); + final Long v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Character getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Object key ) { + return ( ( Character ) key ).charValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TCharLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TCharLongHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharObjectMapDecorator.java b/src/gnu/trove/decorator/TCharObjectMapDecorator.java new file mode 100644 index 0000000..f9b5ba5 --- /dev/null +++ b/src/gnu/trove/decorator/TCharObjectMapDecorator.java @@ -0,0 +1,361 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharObjectMap; +import gnu.trove.iterator.TCharObjectIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharObjectMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharObjectMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharObjectMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharObjectMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharObjectMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharObjectMap to wrap. + */ + public TCharObjectMapDecorator( TCharObjectMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharObjectMap instance. + */ + public TCharObjectMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Character value + * @param value an Object value + * @return the previous value associated with key, + * or null if none was found. + */ + public V put( Character key, V value ) { + char k; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + return _map.put( k, value ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public V get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( ( Character ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.get( k ); + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public V remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( ( Character ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.remove( k ); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharObjectMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharObjectMapDecorator.this.containsKey( k ) && + TCharObjectMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharObjectIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char k = it.key(); + final Character key = (k == _map.getNoEntryKey()) ? null : wrapKey( k ); + final V v = it.value(); + return new Map.Entry() { + private V val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals( key ) + && ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public Character getKey() { + return key; + } + + public V getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public V setValue( V value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharObjectMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return _map.containsValue( val ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( ( ( Character ) key ).charValue() ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Character key ) { + return key.charValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TCharObjectMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TCharObjectHashMapDecorator diff --git a/src/gnu/trove/decorator/TCharSetDecorator.java b/src/gnu/trove/decorator/TCharSetDecorator.java new file mode 100644 index 0000000..cc06b1c --- /dev/null +++ b/src/gnu/trove/decorator/TCharSetDecorator.java @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.set.TCharSet; +import gnu.trove.iterator.TCharIterator; + +import java.io.*; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharSet conform to the java.util.Set API. + * This class simply decorates an underlying TCharSet and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ *

+ * Created: Tue Sep 24 22:08:17 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharSetDecorator extends AbstractSet + implements Set, Externalizable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive set */ + protected TCharSet _set; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharSetDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive set. + * + * @param set the TCharSet to wrap. + */ + public TCharSetDecorator( TCharSet set ) { + super(); + this._set = set; + } + + + /** + * Returns a reference to the set wrapped by this decorator. + * + * @return the wrapped TCharSet instance. + */ + public TCharSet getSet() { + return _set; + } + + + /** + * Inserts a value into the set. + * + * @param value true if the set was modified by the insertion + */ + public boolean add( Character value ) { + return value != null && _set.add( value.charValue() ); + } + + + /** + * Compares this set with another set for equality of their stored + * entries. + * + * @param other an Object value + * @return true if the sets are identical + */ + public boolean equals( Object other ) { + if ( _set.equals( other ) ) { + return true; // comparing two trove sets + } else if ( other instanceof Set ) { + Set that = ( Set ) other; + if ( that.size() != _set.size() ) { + return false; // different sizes, no need to compare + } else { // now we have to do it the hard way + Iterator it = that.iterator(); + for ( int i = that.size(); i-- > 0; ) { + Object val = it.next(); + if ( val instanceof Character ) { + char v = ( ( Character ) val ).charValue(); + if ( _set.contains( v ) ) { + // match, ok to continue + } else { + return false; // no match: we're done + } + } else { + return false; // different type in other set + } + } + return true; // all entries match + } + } else { + return false; + } + } + + + /** + * Empties the set. + */ + public void clear() { + this._set.clear(); + } + + + /** + * Deletes a value from the set. + * + * @param value an Object value + * @return true if the set was modified + */ + public boolean remove( Object value ) { + return value instanceof Character && _set.remove( ( ( Character ) value ).charValue() ); + } + + + /** + * Creates an iterator over the values of the set. + * + * @return an iterator with support for removals in the underlying set + */ + public Iterator iterator() { + return new Iterator() { + private final TCharIterator it = _set.iterator(); + + public Character next() { + return Character.valueOf( it.next() ); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + + /** + * Returns the number of entries in the set. + * + * @return the set's size. + */ + public int size() { + return this._set.size(); + } + + + /** + * Indicates whether set has any entries. + * + * @return true if the set is empty + */ + public boolean isEmpty() { + return this._set.size() == 0; + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean contains( Object o ) { + if ( ! ( o instanceof Character ) ) return false; + return _set.contains( ( ( Character ) o ).charValue() ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SET + _set = ( TCharSet ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SET + out.writeObject( _set ); + } +} // TCharHashSetDecorator diff --git a/src/gnu/trove/decorator/TCharShortMapDecorator.java b/src/gnu/trove/decorator/TCharShortMapDecorator.java new file mode 100644 index 0000000..54c7c70 --- /dev/null +++ b/src/gnu/trove/decorator/TCharShortMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TCharShortMap; +import gnu.trove.iterator.TCharShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TCharShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TCharShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TCharShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TCharShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TCharShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TCharShortMap to wrap. + */ + public TCharShortMapDecorator( TCharShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TCharShortMap instance. + */ + public TCharShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Short(0) if none was found. + */ + public Short put( Character key, Short value ) { + char k; + short v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + short retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Short remove( Object key ) { + char k; + if ( key != null ) { + if ( key instanceof Character ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TCharShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TCharShortMapDecorator.this.containsKey(k) + && TCharShortMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TCharShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + char ik = it.key(); + final Character key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + short iv = it.value(); + final Short v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Character getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Character key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TCharShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Character && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Character wrapKey( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected char unwrapKey( Object key ) { + return ( ( Character ) key ).charValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TCharShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TCharShortHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleByteMapDecorator.java b/src/gnu/trove/decorator/TDoubleByteMapDecorator.java new file mode 100644 index 0000000..0a20cd1 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleByteMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleByteMap; +import gnu.trove.iterator.TDoubleByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleByteMap to wrap. + */ + public TDoubleByteMapDecorator( TDoubleByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleByteMap instance. + */ + public TDoubleByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Byte(0) if none was found. + */ + public Byte put( Double key, Byte value ) { + double k; + byte v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + byte retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Byte remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleByteMapDecorator.this.containsKey(k) + && TDoubleByteMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double ik = it.key(); + final Double key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + byte iv = it.value(); + final Byte v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Double getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Object key ) { + return ( ( Double ) key ).doubleValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TDoubleByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleByteHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleCharMapDecorator.java b/src/gnu/trove/decorator/TDoubleCharMapDecorator.java new file mode 100644 index 0000000..4e66cf3 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleCharMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleCharMap; +import gnu.trove.iterator.TDoubleCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleCharMap to wrap. + */ + public TDoubleCharMapDecorator( TDoubleCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleCharMap instance. + */ + public TDoubleCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Character(0) if none was found. + */ + public Character put( Double key, Character value ) { + double k; + char v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + char retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Character remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleCharMapDecorator.this.containsKey(k) + && TDoubleCharMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double ik = it.key(); + final Double key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + char iv = it.value(); + final Character v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Double getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Object key ) { + return ( ( Double ) key ).doubleValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TDoubleCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleCharHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleDoubleMapDecorator.java b/src/gnu/trove/decorator/TDoubleDoubleMapDecorator.java new file mode 100644 index 0000000..9ada23c --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleDoubleMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleDoubleMap; +import gnu.trove.iterator.TDoubleDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleDoubleMap to wrap. + */ + public TDoubleDoubleMapDecorator( TDoubleDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleDoubleMap instance. + */ + public TDoubleDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Double(0) if none was found. + */ + public Double put( Double key, Double value ) { + double k; + double v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + double retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Double remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleDoubleMapDecorator.this.containsKey(k) + && TDoubleDoubleMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double ik = it.key(); + final Double key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + double iv = it.value(); + final Double v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Double getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Object key ) { + return ( ( Double ) key ).doubleValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TDoubleDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleDoubleHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleFloatMapDecorator.java b/src/gnu/trove/decorator/TDoubleFloatMapDecorator.java new file mode 100644 index 0000000..34a2139 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleFloatMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleFloatMap; +import gnu.trove.iterator.TDoubleFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleFloatMap to wrap. + */ + public TDoubleFloatMapDecorator( TDoubleFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleFloatMap instance. + */ + public TDoubleFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Float(0) if none was found. + */ + public Float put( Double key, Float value ) { + double k; + float v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + float retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Float remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleFloatMapDecorator.this.containsKey(k) + && TDoubleFloatMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double ik = it.key(); + final Double key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + float iv = it.value(); + final Float v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Double getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Object key ) { + return ( ( Double ) key ).doubleValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TDoubleFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleFloatHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleIntMapDecorator.java b/src/gnu/trove/decorator/TDoubleIntMapDecorator.java new file mode 100644 index 0000000..055ef65 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleIntMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleIntMap; +import gnu.trove.iterator.TDoubleIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleIntMap to wrap. + */ + public TDoubleIntMapDecorator( TDoubleIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleIntMap instance. + */ + public TDoubleIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( Double key, Integer value ) { + double k; + int v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + int retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Integer remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleIntMapDecorator.this.containsKey(k) + && TDoubleIntMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double ik = it.key(); + final Double key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + int iv = it.value(); + final Integer v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Double getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Object key ) { + return ( ( Double ) key ).doubleValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TDoubleIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleIntHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleListDecorator.java b/src/gnu/trove/decorator/TDoubleListDecorator.java new file mode 100644 index 0000000..f1444e3 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleListDecorator.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.list.TDoubleList; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractList; +import java.util.List; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleList conform to the java.util.List API. + * This class simply decorates an underlying TDoubleList and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * + * @author Robert D. Eden + */ +public class TDoubleListDecorator extends AbstractList + implements List, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive list */ + protected TDoubleList list; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleListDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param list the TDoubleList to wrap. + */ + public TDoubleListDecorator( TDoubleList list ) { + super(); + this.list = list; + } + + + /** + * Returns a reference to the list wrapped by this decorator. + * + * @return the wrapped TDoubleList instance. + */ + public TDoubleList getList() { + return list; + } + + + @Override + public int size() { + return list.size(); + } + + + @Override + public Double get( int index ) { + double value = list.get( index ); + if ( value == list.getNoEntryValue() ) return null; + else return Double.valueOf( value ); + } + + + @Override + public Double set( int index, Double value ) { + double previous_value = list.set( index, value ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Double.valueOf( previous_value ); + } + + + @Override + public void add( int index, Double value ) { + list.insert( index, value.doubleValue() ); + } + + + @Override + public Double remove( int index ) { + double previous_value = list.removeAt( index ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Double.valueOf( previous_value ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + list = ( TDoubleList ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // LIST + out.writeObject( list ); + } + +} diff --git a/src/gnu/trove/decorator/TDoubleLongMapDecorator.java b/src/gnu/trove/decorator/TDoubleLongMapDecorator.java new file mode 100644 index 0000000..0ec4dd5 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleLongMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleLongMap; +import gnu.trove.iterator.TDoubleLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleLongMap to wrap. + */ + public TDoubleLongMapDecorator( TDoubleLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleLongMap instance. + */ + public TDoubleLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Long(0) if none was found. + */ + public Long put( Double key, Long value ) { + double k; + long v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + long retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Long remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleLongMapDecorator.this.containsKey(k) + && TDoubleLongMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double ik = it.key(); + final Double key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + long iv = it.value(); + final Long v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Double getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Object key ) { + return ( ( Double ) key ).doubleValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TDoubleLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleLongHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleObjectMapDecorator.java b/src/gnu/trove/decorator/TDoubleObjectMapDecorator.java new file mode 100644 index 0000000..29c3bbc --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleObjectMapDecorator.java @@ -0,0 +1,361 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleObjectMap; +import gnu.trove.iterator.TDoubleObjectIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleObjectMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleObjectMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleObjectMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleObjectMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleObjectMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleObjectMap to wrap. + */ + public TDoubleObjectMapDecorator( TDoubleObjectMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleObjectMap instance. + */ + public TDoubleObjectMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Double value + * @param value an Object value + * @return the previous value associated with key, + * or null if none was found. + */ + public V put( Double key, V value ) { + double k; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + return _map.put( k, value ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public V get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( ( Double ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.get( k ); + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public V remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( ( Double ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.remove( k ); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleObjectMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleObjectMapDecorator.this.containsKey( k ) && + TDoubleObjectMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleObjectIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double k = it.key(); + final Double key = (k == _map.getNoEntryKey()) ? null : wrapKey( k ); + final V v = it.value(); + return new Map.Entry() { + private V val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals( key ) + && ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public Double getKey() { + return key; + } + + public V getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public V setValue( V value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleObjectMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return _map.containsValue( val ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( ( ( Double ) key ).doubleValue() ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Double key ) { + return key.doubleValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TDoubleObjectMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleObjectHashMapDecorator diff --git a/src/gnu/trove/decorator/TDoubleSetDecorator.java b/src/gnu/trove/decorator/TDoubleSetDecorator.java new file mode 100644 index 0000000..590b840 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleSetDecorator.java @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.set.TDoubleSet; +import gnu.trove.iterator.TDoubleIterator; + +import java.io.*; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleSet conform to the java.util.Set API. + * This class simply decorates an underlying TDoubleSet and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ *

+ * Created: Tue Sep 24 22:08:17 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleSetDecorator extends AbstractSet + implements Set, Externalizable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive set */ + protected TDoubleSet _set; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleSetDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive set. + * + * @param set the TDoubleSet to wrap. + */ + public TDoubleSetDecorator( TDoubleSet set ) { + super(); + this._set = set; + } + + + /** + * Returns a reference to the set wrapped by this decorator. + * + * @return the wrapped TDoubleSet instance. + */ + public TDoubleSet getSet() { + return _set; + } + + + /** + * Inserts a value into the set. + * + * @param value true if the set was modified by the insertion + */ + public boolean add( Double value ) { + return value != null && _set.add( value.doubleValue() ); + } + + + /** + * Compares this set with another set for equality of their stored + * entries. + * + * @param other an Object value + * @return true if the sets are identical + */ + public boolean equals( Object other ) { + if ( _set.equals( other ) ) { + return true; // comparing two trove sets + } else if ( other instanceof Set ) { + Set that = ( Set ) other; + if ( that.size() != _set.size() ) { + return false; // different sizes, no need to compare + } else { // now we have to do it the hard way + Iterator it = that.iterator(); + for ( int i = that.size(); i-- > 0; ) { + Object val = it.next(); + if ( val instanceof Double ) { + double v = ( ( Double ) val ).doubleValue(); + if ( _set.contains( v ) ) { + // match, ok to continue + } else { + return false; // no match: we're done + } + } else { + return false; // different type in other set + } + } + return true; // all entries match + } + } else { + return false; + } + } + + + /** + * Empties the set. + */ + public void clear() { + this._set.clear(); + } + + + /** + * Deletes a value from the set. + * + * @param value an Object value + * @return true if the set was modified + */ + public boolean remove( Object value ) { + return value instanceof Double && _set.remove( ( ( Double ) value ).doubleValue() ); + } + + + /** + * Creates an iterator over the values of the set. + * + * @return an iterator with support for removals in the underlying set + */ + public Iterator iterator() { + return new Iterator() { + private final TDoubleIterator it = _set.iterator(); + + public Double next() { + return Double.valueOf( it.next() ); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + + /** + * Returns the number of entries in the set. + * + * @return the set's size. + */ + public int size() { + return this._set.size(); + } + + + /** + * Indicates whether set has any entries. + * + * @return true if the set is empty + */ + public boolean isEmpty() { + return this._set.size() == 0; + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean contains( Object o ) { + if ( ! ( o instanceof Double ) ) return false; + return _set.contains( ( ( Double ) o ).doubleValue() ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SET + _set = ( TDoubleSet ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SET + out.writeObject( _set ); + } +} // TDoubleHashSetDecorator diff --git a/src/gnu/trove/decorator/TDoubleShortMapDecorator.java b/src/gnu/trove/decorator/TDoubleShortMapDecorator.java new file mode 100644 index 0000000..e1676e8 --- /dev/null +++ b/src/gnu/trove/decorator/TDoubleShortMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TDoubleShortMap; +import gnu.trove.iterator.TDoubleShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TDoubleShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TDoubleShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TDoubleShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TDoubleShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TDoubleShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TDoubleShortMap to wrap. + */ + public TDoubleShortMapDecorator( TDoubleShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TDoubleShortMap instance. + */ + public TDoubleShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Short(0) if none was found. + */ + public Short put( Double key, Short value ) { + double k; + short v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + short retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Short remove( Object key ) { + double k; + if ( key != null ) { + if ( key instanceof Double ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TDoubleShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TDoubleShortMapDecorator.this.containsKey(k) + && TDoubleShortMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TDoubleShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + double ik = it.key(); + final Double key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + short iv = it.value(); + final Short v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Double getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Double key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TDoubleShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Double && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Double wrapKey( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected double unwrapKey( Object key ) { + return ( ( Double ) key ).doubleValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TDoubleShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TDoubleShortHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatByteMapDecorator.java b/src/gnu/trove/decorator/TFloatByteMapDecorator.java new file mode 100644 index 0000000..765fb11 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatByteMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatByteMap; +import gnu.trove.iterator.TFloatByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatByteMap to wrap. + */ + public TFloatByteMapDecorator( TFloatByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatByteMap instance. + */ + public TFloatByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Byte(0) if none was found. + */ + public Byte put( Float key, Byte value ) { + float k; + byte v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + byte retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Byte remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatByteMapDecorator.this.containsKey(k) + && TFloatByteMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float ik = it.key(); + final Float key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + byte iv = it.value(); + final Byte v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Float getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Object key ) { + return ( ( Float ) key ).floatValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TFloatByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TFloatByteHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatCharMapDecorator.java b/src/gnu/trove/decorator/TFloatCharMapDecorator.java new file mode 100644 index 0000000..62632d4 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatCharMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatCharMap; +import gnu.trove.iterator.TFloatCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatCharMap to wrap. + */ + public TFloatCharMapDecorator( TFloatCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatCharMap instance. + */ + public TFloatCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Character(0) if none was found. + */ + public Character put( Float key, Character value ) { + float k; + char v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + char retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Character remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatCharMapDecorator.this.containsKey(k) + && TFloatCharMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float ik = it.key(); + final Float key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + char iv = it.value(); + final Character v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Float getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Object key ) { + return ( ( Float ) key ).floatValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TFloatCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TFloatCharHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatDoubleMapDecorator.java b/src/gnu/trove/decorator/TFloatDoubleMapDecorator.java new file mode 100644 index 0000000..e8db2ad --- /dev/null +++ b/src/gnu/trove/decorator/TFloatDoubleMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatDoubleMap; +import gnu.trove.iterator.TFloatDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatDoubleMap to wrap. + */ + public TFloatDoubleMapDecorator( TFloatDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatDoubleMap instance. + */ + public TFloatDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Double(0) if none was found. + */ + public Double put( Float key, Double value ) { + float k; + double v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + double retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Double remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatDoubleMapDecorator.this.containsKey(k) + && TFloatDoubleMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float ik = it.key(); + final Float key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + double iv = it.value(); + final Double v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Float getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Object key ) { + return ( ( Float ) key ).floatValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TFloatDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TFloatDoubleHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatFloatMapDecorator.java b/src/gnu/trove/decorator/TFloatFloatMapDecorator.java new file mode 100644 index 0000000..5a6c327 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatFloatMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatFloatMap; +import gnu.trove.iterator.TFloatFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatFloatMap to wrap. + */ + public TFloatFloatMapDecorator( TFloatFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatFloatMap instance. + */ + public TFloatFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Float(0) if none was found. + */ + public Float put( Float key, Float value ) { + float k; + float v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + float retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Float remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatFloatMapDecorator.this.containsKey(k) + && TFloatFloatMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float ik = it.key(); + final Float key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + float iv = it.value(); + final Float v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Float getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Object key ) { + return ( ( Float ) key ).floatValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TFloatFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TFloatFloatHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatIntMapDecorator.java b/src/gnu/trove/decorator/TFloatIntMapDecorator.java new file mode 100644 index 0000000..8a6b850 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatIntMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatIntMap; +import gnu.trove.iterator.TFloatIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatIntMap to wrap. + */ + public TFloatIntMapDecorator( TFloatIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatIntMap instance. + */ + public TFloatIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( Float key, Integer value ) { + float k; + int v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + int retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Integer remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatIntMapDecorator.this.containsKey(k) + && TFloatIntMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float ik = it.key(); + final Float key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + int iv = it.value(); + final Integer v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Float getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Object key ) { + return ( ( Float ) key ).floatValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TFloatIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TFloatIntHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatListDecorator.java b/src/gnu/trove/decorator/TFloatListDecorator.java new file mode 100644 index 0000000..c0479c2 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatListDecorator.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.list.TFloatList; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractList; +import java.util.List; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatList conform to the java.util.List API. + * This class simply decorates an underlying TFloatList and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * + * @author Robert D. Eden + */ +public class TFloatListDecorator extends AbstractList + implements List, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive list */ + protected TFloatList list; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatListDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param list the TFloatList to wrap. + */ + public TFloatListDecorator( TFloatList list ) { + super(); + this.list = list; + } + + + /** + * Returns a reference to the list wrapped by this decorator. + * + * @return the wrapped TFloatList instance. + */ + public TFloatList getList() { + return list; + } + + + @Override + public int size() { + return list.size(); + } + + + @Override + public Float get( int index ) { + float value = list.get( index ); + if ( value == list.getNoEntryValue() ) return null; + else return Float.valueOf( value ); + } + + + @Override + public Float set( int index, Float value ) { + float previous_value = list.set( index, value ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Float.valueOf( previous_value ); + } + + + @Override + public void add( int index, Float value ) { + list.insert( index, value.floatValue() ); + } + + + @Override + public Float remove( int index ) { + float previous_value = list.removeAt( index ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Float.valueOf( previous_value ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + list = ( TFloatList ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // LIST + out.writeObject( list ); + } + +} diff --git a/src/gnu/trove/decorator/TFloatLongMapDecorator.java b/src/gnu/trove/decorator/TFloatLongMapDecorator.java new file mode 100644 index 0000000..7759aff --- /dev/null +++ b/src/gnu/trove/decorator/TFloatLongMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatLongMap; +import gnu.trove.iterator.TFloatLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatLongMap to wrap. + */ + public TFloatLongMapDecorator( TFloatLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatLongMap instance. + */ + public TFloatLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Long(0) if none was found. + */ + public Long put( Float key, Long value ) { + float k; + long v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + long retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Long remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatLongMapDecorator.this.containsKey(k) + && TFloatLongMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float ik = it.key(); + final Float key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + long iv = it.value(); + final Long v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Float getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Object key ) { + return ( ( Float ) key ).floatValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TFloatLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TFloatLongHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatObjectMapDecorator.java b/src/gnu/trove/decorator/TFloatObjectMapDecorator.java new file mode 100644 index 0000000..ebfe306 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatObjectMapDecorator.java @@ -0,0 +1,361 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatObjectMap; +import gnu.trove.iterator.TFloatObjectIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatObjectMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatObjectMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatObjectMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatObjectMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatObjectMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatObjectMap to wrap. + */ + public TFloatObjectMapDecorator( TFloatObjectMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatObjectMap instance. + */ + public TFloatObjectMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Float value + * @param value an Object value + * @return the previous value associated with key, + * or null if none was found. + */ + public V put( Float key, V value ) { + float k; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + return _map.put( k, value ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public V get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( ( Float ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.get( k ); + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public V remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( ( Float ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.remove( k ); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatObjectMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatObjectMapDecorator.this.containsKey( k ) && + TFloatObjectMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatObjectIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float k = it.key(); + final Float key = (k == _map.getNoEntryKey()) ? null : wrapKey( k ); + final V v = it.value(); + return new Map.Entry() { + private V val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals( key ) + && ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public Float getKey() { + return key; + } + + public V getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public V setValue( V value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatObjectMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return _map.containsValue( val ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( ( ( Float ) key ).floatValue() ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Float key ) { + return key.floatValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TFloatObjectMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TFloatObjectHashMapDecorator diff --git a/src/gnu/trove/decorator/TFloatSetDecorator.java b/src/gnu/trove/decorator/TFloatSetDecorator.java new file mode 100644 index 0000000..a3aee84 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatSetDecorator.java @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.set.TFloatSet; +import gnu.trove.iterator.TFloatIterator; + +import java.io.*; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatSet conform to the java.util.Set API. + * This class simply decorates an underlying TFloatSet and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ *

+ * Created: Tue Sep 24 22:08:17 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatSetDecorator extends AbstractSet + implements Set, Externalizable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive set */ + protected TFloatSet _set; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatSetDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive set. + * + * @param set the TFloatSet to wrap. + */ + public TFloatSetDecorator( TFloatSet set ) { + super(); + this._set = set; + } + + + /** + * Returns a reference to the set wrapped by this decorator. + * + * @return the wrapped TFloatSet instance. + */ + public TFloatSet getSet() { + return _set; + } + + + /** + * Inserts a value into the set. + * + * @param value true if the set was modified by the insertion + */ + public boolean add( Float value ) { + return value != null && _set.add( value.floatValue() ); + } + + + /** + * Compares this set with another set for equality of their stored + * entries. + * + * @param other an Object value + * @return true if the sets are identical + */ + public boolean equals( Object other ) { + if ( _set.equals( other ) ) { + return true; // comparing two trove sets + } else if ( other instanceof Set ) { + Set that = ( Set ) other; + if ( that.size() != _set.size() ) { + return false; // different sizes, no need to compare + } else { // now we have to do it the hard way + Iterator it = that.iterator(); + for ( int i = that.size(); i-- > 0; ) { + Object val = it.next(); + if ( val instanceof Float ) { + float v = ( ( Float ) val ).floatValue(); + if ( _set.contains( v ) ) { + // match, ok to continue + } else { + return false; // no match: we're done + } + } else { + return false; // different type in other set + } + } + return true; // all entries match + } + } else { + return false; + } + } + + + /** + * Empties the set. + */ + public void clear() { + this._set.clear(); + } + + + /** + * Deletes a value from the set. + * + * @param value an Object value + * @return true if the set was modified + */ + public boolean remove( Object value ) { + return value instanceof Float && _set.remove( ( ( Float ) value ).floatValue() ); + } + + + /** + * Creates an iterator over the values of the set. + * + * @return an iterator with support for removals in the underlying set + */ + public Iterator iterator() { + return new Iterator() { + private final TFloatIterator it = _set.iterator(); + + public Float next() { + return Float.valueOf( it.next() ); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + + /** + * Returns the number of entries in the set. + * + * @return the set's size. + */ + public int size() { + return this._set.size(); + } + + + /** + * Indicates whether set has any entries. + * + * @return true if the set is empty + */ + public boolean isEmpty() { + return this._set.size() == 0; + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean contains( Object o ) { + if ( ! ( o instanceof Float ) ) return false; + return _set.contains( ( ( Float ) o ).floatValue() ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SET + _set = ( TFloatSet ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SET + out.writeObject( _set ); + } +} // TFloatHashSetDecorator diff --git a/src/gnu/trove/decorator/TFloatShortMapDecorator.java b/src/gnu/trove/decorator/TFloatShortMapDecorator.java new file mode 100644 index 0000000..372bf70 --- /dev/null +++ b/src/gnu/trove/decorator/TFloatShortMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TFloatShortMap; +import gnu.trove.iterator.TFloatShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TFloatShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TFloatShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TFloatShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TFloatShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TFloatShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TFloatShortMap to wrap. + */ + public TFloatShortMapDecorator( TFloatShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TFloatShortMap instance. + */ + public TFloatShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Short(0) if none was found. + */ + public Short put( Float key, Short value ) { + float k; + short v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + short retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Short remove( Object key ) { + float k; + if ( key != null ) { + if ( key instanceof Float ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TFloatShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TFloatShortMapDecorator.this.containsKey(k) + && TFloatShortMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TFloatShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + float ik = it.key(); + final Float key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + short iv = it.value(); + final Short v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Float getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Float key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TFloatShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Float && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Float wrapKey( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected float unwrapKey( Object key ) { + return ( ( Float ) key ).floatValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TFloatShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TFloatShortHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntByteMapDecorator.java b/src/gnu/trove/decorator/TIntByteMapDecorator.java new file mode 100644 index 0000000..15f2ecd --- /dev/null +++ b/src/gnu/trove/decorator/TIntByteMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntByteMap; +import gnu.trove.iterator.TIntByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntByteMap to wrap. + */ + public TIntByteMapDecorator( TIntByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntByteMap instance. + */ + public TIntByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Byte(0) if none was found. + */ + public Byte put( Integer key, Byte value ) { + int k; + byte v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + byte retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Byte remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntByteMapDecorator.this.containsKey(k) + && TIntByteMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int ik = it.key(); + final Integer key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + byte iv = it.value(); + final Byte v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Integer getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Object key ) { + return ( ( Integer ) key ).intValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TIntByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TIntByteHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntCharMapDecorator.java b/src/gnu/trove/decorator/TIntCharMapDecorator.java new file mode 100644 index 0000000..a1f1860 --- /dev/null +++ b/src/gnu/trove/decorator/TIntCharMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntCharMap; +import gnu.trove.iterator.TIntCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntCharMap to wrap. + */ + public TIntCharMapDecorator( TIntCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntCharMap instance. + */ + public TIntCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Character(0) if none was found. + */ + public Character put( Integer key, Character value ) { + int k; + char v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + char retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Character remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntCharMapDecorator.this.containsKey(k) + && TIntCharMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int ik = it.key(); + final Integer key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + char iv = it.value(); + final Character v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Integer getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Object key ) { + return ( ( Integer ) key ).intValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TIntCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TIntCharHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntDoubleMapDecorator.java b/src/gnu/trove/decorator/TIntDoubleMapDecorator.java new file mode 100644 index 0000000..ad82811 --- /dev/null +++ b/src/gnu/trove/decorator/TIntDoubleMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntDoubleMap; +import gnu.trove.iterator.TIntDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntDoubleMap to wrap. + */ + public TIntDoubleMapDecorator( TIntDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntDoubleMap instance. + */ + public TIntDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Double(0) if none was found. + */ + public Double put( Integer key, Double value ) { + int k; + double v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + double retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Double remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntDoubleMapDecorator.this.containsKey(k) + && TIntDoubleMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int ik = it.key(); + final Integer key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + double iv = it.value(); + final Double v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Integer getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Object key ) { + return ( ( Integer ) key ).intValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TIntDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TIntDoubleHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntFloatMapDecorator.java b/src/gnu/trove/decorator/TIntFloatMapDecorator.java new file mode 100644 index 0000000..7751127 --- /dev/null +++ b/src/gnu/trove/decorator/TIntFloatMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntFloatMap; +import gnu.trove.iterator.TIntFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntFloatMap to wrap. + */ + public TIntFloatMapDecorator( TIntFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntFloatMap instance. + */ + public TIntFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Float(0) if none was found. + */ + public Float put( Integer key, Float value ) { + int k; + float v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + float retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Float remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntFloatMapDecorator.this.containsKey(k) + && TIntFloatMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int ik = it.key(); + final Integer key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + float iv = it.value(); + final Float v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Integer getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Object key ) { + return ( ( Integer ) key ).intValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TIntFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TIntFloatHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntIntMapDecorator.java b/src/gnu/trove/decorator/TIntIntMapDecorator.java new file mode 100644 index 0000000..a4ae9fd --- /dev/null +++ b/src/gnu/trove/decorator/TIntIntMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntIntMap; +import gnu.trove.iterator.TIntIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntIntMap to wrap. + */ + public TIntIntMapDecorator( TIntIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntIntMap instance. + */ + public TIntIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( Integer key, Integer value ) { + int k; + int v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + int retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Integer remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntIntMapDecorator.this.containsKey(k) + && TIntIntMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int ik = it.key(); + final Integer key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + int iv = it.value(); + final Integer v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Integer getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Object key ) { + return ( ( Integer ) key ).intValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TIntIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TIntIntHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntListDecorator.java b/src/gnu/trove/decorator/TIntListDecorator.java new file mode 100644 index 0000000..4af2124 --- /dev/null +++ b/src/gnu/trove/decorator/TIntListDecorator.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.list.TIntList; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractList; +import java.util.List; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntList conform to the java.util.List API. + * This class simply decorates an underlying TIntList and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * + * @author Robert D. Eden + */ +public class TIntListDecorator extends AbstractList + implements List, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive list */ + protected TIntList list; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntListDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param list the TIntList to wrap. + */ + public TIntListDecorator( TIntList list ) { + super(); + this.list = list; + } + + + /** + * Returns a reference to the list wrapped by this decorator. + * + * @return the wrapped TIntList instance. + */ + public TIntList getList() { + return list; + } + + + @Override + public int size() { + return list.size(); + } + + + @Override + public Integer get( int index ) { + int value = list.get( index ); + if ( value == list.getNoEntryValue() ) return null; + else return Integer.valueOf( value ); + } + + + @Override + public Integer set( int index, Integer value ) { + int previous_value = list.set( index, value ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Integer.valueOf( previous_value ); + } + + + @Override + public void add( int index, Integer value ) { + list.insert( index, value.intValue() ); + } + + + @Override + public Integer remove( int index ) { + int previous_value = list.removeAt( index ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Integer.valueOf( previous_value ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + list = ( TIntList ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // LIST + out.writeObject( list ); + } + +} diff --git a/src/gnu/trove/decorator/TIntLongMapDecorator.java b/src/gnu/trove/decorator/TIntLongMapDecorator.java new file mode 100644 index 0000000..3ab2f7b --- /dev/null +++ b/src/gnu/trove/decorator/TIntLongMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntLongMap; +import gnu.trove.iterator.TIntLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntLongMap to wrap. + */ + public TIntLongMapDecorator( TIntLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntLongMap instance. + */ + public TIntLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Long(0) if none was found. + */ + public Long put( Integer key, Long value ) { + int k; + long v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + long retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Long remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntLongMapDecorator.this.containsKey(k) + && TIntLongMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int ik = it.key(); + final Integer key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + long iv = it.value(); + final Long v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Integer getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Object key ) { + return ( ( Integer ) key ).intValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TIntLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TIntLongHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntObjectMapDecorator.java b/src/gnu/trove/decorator/TIntObjectMapDecorator.java new file mode 100644 index 0000000..aa14aa2 --- /dev/null +++ b/src/gnu/trove/decorator/TIntObjectMapDecorator.java @@ -0,0 +1,361 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntObjectMap; +import gnu.trove.iterator.TIntObjectIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntObjectMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntObjectMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntObjectMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntObjectMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntObjectMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntObjectMap to wrap. + */ + public TIntObjectMapDecorator( TIntObjectMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntObjectMap instance. + */ + public TIntObjectMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Integer value + * @param value an Object value + * @return the previous value associated with key, + * or null if none was found. + */ + public V put( Integer key, V value ) { + int k; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + return _map.put( k, value ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public V get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( ( Integer ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.get( k ); + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public V remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( ( Integer ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.remove( k ); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntObjectMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntObjectMapDecorator.this.containsKey( k ) && + TIntObjectMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntObjectIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int k = it.key(); + final Integer key = (k == _map.getNoEntryKey()) ? null : wrapKey( k ); + final V v = it.value(); + return new Map.Entry() { + private V val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals( key ) + && ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public Integer getKey() { + return key; + } + + public V getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public V setValue( V value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntObjectMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return _map.containsValue( val ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( ( ( Integer ) key ).intValue() ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Integer key ) { + return key.intValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TIntObjectMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TIntObjectHashMapDecorator diff --git a/src/gnu/trove/decorator/TIntSetDecorator.java b/src/gnu/trove/decorator/TIntSetDecorator.java new file mode 100644 index 0000000..69026b1 --- /dev/null +++ b/src/gnu/trove/decorator/TIntSetDecorator.java @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.set.TIntSet; +import gnu.trove.iterator.TIntIterator; + +import java.io.*; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntSet conform to the java.util.Set API. + * This class simply decorates an underlying TIntSet and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ *

+ * Created: Tue Sep 24 22:08:17 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntSetDecorator extends AbstractSet + implements Set, Externalizable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive set */ + protected TIntSet _set; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntSetDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive set. + * + * @param set the TIntSet to wrap. + */ + public TIntSetDecorator( TIntSet set ) { + super(); + this._set = set; + } + + + /** + * Returns a reference to the set wrapped by this decorator. + * + * @return the wrapped TIntSet instance. + */ + public TIntSet getSet() { + return _set; + } + + + /** + * Inserts a value into the set. + * + * @param value true if the set was modified by the insertion + */ + public boolean add( Integer value ) { + return value != null && _set.add( value.intValue() ); + } + + + /** + * Compares this set with another set for equality of their stored + * entries. + * + * @param other an Object value + * @return true if the sets are identical + */ + public boolean equals( Object other ) { + if ( _set.equals( other ) ) { + return true; // comparing two trove sets + } else if ( other instanceof Set ) { + Set that = ( Set ) other; + if ( that.size() != _set.size() ) { + return false; // different sizes, no need to compare + } else { // now we have to do it the hard way + Iterator it = that.iterator(); + for ( int i = that.size(); i-- > 0; ) { + Object val = it.next(); + if ( val instanceof Integer ) { + int v = ( ( Integer ) val ).intValue(); + if ( _set.contains( v ) ) { + // match, ok to continue + } else { + return false; // no match: we're done + } + } else { + return false; // different type in other set + } + } + return true; // all entries match + } + } else { + return false; + } + } + + + /** + * Empties the set. + */ + public void clear() { + this._set.clear(); + } + + + /** + * Deletes a value from the set. + * + * @param value an Object value + * @return true if the set was modified + */ + public boolean remove( Object value ) { + return value instanceof Integer && _set.remove( ( ( Integer ) value ).intValue() ); + } + + + /** + * Creates an iterator over the values of the set. + * + * @return an iterator with support for removals in the underlying set + */ + public Iterator iterator() { + return new Iterator() { + private final TIntIterator it = _set.iterator(); + + public Integer next() { + return Integer.valueOf( it.next() ); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + + /** + * Returns the number of entries in the set. + * + * @return the set's size. + */ + public int size() { + return this._set.size(); + } + + + /** + * Indicates whether set has any entries. + * + * @return true if the set is empty + */ + public boolean isEmpty() { + return this._set.size() == 0; + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean contains( Object o ) { + if ( ! ( o instanceof Integer ) ) return false; + return _set.contains( ( ( Integer ) o ).intValue() ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SET + _set = ( TIntSet ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SET + out.writeObject( _set ); + } +} // TIntHashSetDecorator diff --git a/src/gnu/trove/decorator/TIntShortMapDecorator.java b/src/gnu/trove/decorator/TIntShortMapDecorator.java new file mode 100644 index 0000000..33bc570 --- /dev/null +++ b/src/gnu/trove/decorator/TIntShortMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TIntShortMap; +import gnu.trove.iterator.TIntShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TIntShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TIntShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TIntShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TIntShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TIntShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TIntShortMap to wrap. + */ + public TIntShortMapDecorator( TIntShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TIntShortMap instance. + */ + public TIntShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Short(0) if none was found. + */ + public Short put( Integer key, Short value ) { + int k; + short v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + short retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Short remove( Object key ) { + int k; + if ( key != null ) { + if ( key instanceof Integer ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TIntShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TIntShortMapDecorator.this.containsKey(k) + && TIntShortMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TIntShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + int ik = it.key(); + final Integer key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + short iv = it.value(); + final Short v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Integer getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Integer key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TIntShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Integer && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Integer wrapKey( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected int unwrapKey( Object key ) { + return ( ( Integer ) key ).intValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TIntShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TIntShortHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongByteMapDecorator.java b/src/gnu/trove/decorator/TLongByteMapDecorator.java new file mode 100644 index 0000000..e8f225d --- /dev/null +++ b/src/gnu/trove/decorator/TLongByteMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongByteMap; +import gnu.trove.iterator.TLongByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongByteMap to wrap. + */ + public TLongByteMapDecorator( TLongByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongByteMap instance. + */ + public TLongByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Byte(0) if none was found. + */ + public Byte put( Long key, Byte value ) { + long k; + byte v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + byte retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Byte remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongByteMapDecorator.this.containsKey(k) + && TLongByteMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long ik = it.key(); + final Long key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + byte iv = it.value(); + final Byte v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Long getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Object key ) { + return ( ( Long ) key ).longValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TLongByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TLongByteHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongCharMapDecorator.java b/src/gnu/trove/decorator/TLongCharMapDecorator.java new file mode 100644 index 0000000..56c1101 --- /dev/null +++ b/src/gnu/trove/decorator/TLongCharMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongCharMap; +import gnu.trove.iterator.TLongCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongCharMap to wrap. + */ + public TLongCharMapDecorator( TLongCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongCharMap instance. + */ + public TLongCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Character(0) if none was found. + */ + public Character put( Long key, Character value ) { + long k; + char v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + char retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Character remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongCharMapDecorator.this.containsKey(k) + && TLongCharMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long ik = it.key(); + final Long key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + char iv = it.value(); + final Character v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Long getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Object key ) { + return ( ( Long ) key ).longValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TLongCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TLongCharHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongDoubleMapDecorator.java b/src/gnu/trove/decorator/TLongDoubleMapDecorator.java new file mode 100644 index 0000000..b86152a --- /dev/null +++ b/src/gnu/trove/decorator/TLongDoubleMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongDoubleMap; +import gnu.trove.iterator.TLongDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongDoubleMap to wrap. + */ + public TLongDoubleMapDecorator( TLongDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongDoubleMap instance. + */ + public TLongDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Double(0) if none was found. + */ + public Double put( Long key, Double value ) { + long k; + double v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + double retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Double remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongDoubleMapDecorator.this.containsKey(k) + && TLongDoubleMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long ik = it.key(); + final Long key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + double iv = it.value(); + final Double v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Long getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Object key ) { + return ( ( Long ) key ).longValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TLongDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TLongDoubleHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongFloatMapDecorator.java b/src/gnu/trove/decorator/TLongFloatMapDecorator.java new file mode 100644 index 0000000..ddcb0b0 --- /dev/null +++ b/src/gnu/trove/decorator/TLongFloatMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongFloatMap; +import gnu.trove.iterator.TLongFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongFloatMap to wrap. + */ + public TLongFloatMapDecorator( TLongFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongFloatMap instance. + */ + public TLongFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Float(0) if none was found. + */ + public Float put( Long key, Float value ) { + long k; + float v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + float retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Float remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongFloatMapDecorator.this.containsKey(k) + && TLongFloatMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long ik = it.key(); + final Long key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + float iv = it.value(); + final Float v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Long getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Object key ) { + return ( ( Long ) key ).longValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TLongFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TLongFloatHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongIntMapDecorator.java b/src/gnu/trove/decorator/TLongIntMapDecorator.java new file mode 100644 index 0000000..baffba3 --- /dev/null +++ b/src/gnu/trove/decorator/TLongIntMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongIntMap; +import gnu.trove.iterator.TLongIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongIntMap to wrap. + */ + public TLongIntMapDecorator( TLongIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongIntMap instance. + */ + public TLongIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( Long key, Integer value ) { + long k; + int v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + int retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Integer remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongIntMapDecorator.this.containsKey(k) + && TLongIntMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long ik = it.key(); + final Long key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + int iv = it.value(); + final Integer v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Long getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Object key ) { + return ( ( Long ) key ).longValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TLongIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TLongIntHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongListDecorator.java b/src/gnu/trove/decorator/TLongListDecorator.java new file mode 100644 index 0000000..bc620b0 --- /dev/null +++ b/src/gnu/trove/decorator/TLongListDecorator.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.list.TLongList; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractList; +import java.util.List; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongList conform to the java.util.List API. + * This class simply decorates an underlying TLongList and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * + * @author Robert D. Eden + */ +public class TLongListDecorator extends AbstractList + implements List, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive list */ + protected TLongList list; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongListDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param list the TLongList to wrap. + */ + public TLongListDecorator( TLongList list ) { + super(); + this.list = list; + } + + + /** + * Returns a reference to the list wrapped by this decorator. + * + * @return the wrapped TLongList instance. + */ + public TLongList getList() { + return list; + } + + + @Override + public int size() { + return list.size(); + } + + + @Override + public Long get( int index ) { + long value = list.get( index ); + if ( value == list.getNoEntryValue() ) return null; + else return Long.valueOf( value ); + } + + + @Override + public Long set( int index, Long value ) { + long previous_value = list.set( index, value ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Long.valueOf( previous_value ); + } + + + @Override + public void add( int index, Long value ) { + list.insert( index, value.longValue() ); + } + + + @Override + public Long remove( int index ) { + long previous_value = list.removeAt( index ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Long.valueOf( previous_value ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + list = ( TLongList ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // LIST + out.writeObject( list ); + } + +} diff --git a/src/gnu/trove/decorator/TLongLongMapDecorator.java b/src/gnu/trove/decorator/TLongLongMapDecorator.java new file mode 100644 index 0000000..4f99f5f --- /dev/null +++ b/src/gnu/trove/decorator/TLongLongMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongLongMap; +import gnu.trove.iterator.TLongLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongLongMap to wrap. + */ + public TLongLongMapDecorator( TLongLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongLongMap instance. + */ + public TLongLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Long(0) if none was found. + */ + public Long put( Long key, Long value ) { + long k; + long v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + long retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Long remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongLongMapDecorator.this.containsKey(k) + && TLongLongMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long ik = it.key(); + final Long key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + long iv = it.value(); + final Long v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Long getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Object key ) { + return ( ( Long ) key ).longValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TLongLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TLongLongHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongObjectMapDecorator.java b/src/gnu/trove/decorator/TLongObjectMapDecorator.java new file mode 100644 index 0000000..884d258 --- /dev/null +++ b/src/gnu/trove/decorator/TLongObjectMapDecorator.java @@ -0,0 +1,361 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongObjectMap; +import gnu.trove.iterator.TLongObjectIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongObjectMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongObjectMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongObjectMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongObjectMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongObjectMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongObjectMap to wrap. + */ + public TLongObjectMapDecorator( TLongObjectMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongObjectMap instance. + */ + public TLongObjectMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Long value + * @param value an Object value + * @return the previous value associated with key, + * or null if none was found. + */ + public V put( Long key, V value ) { + long k; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + return _map.put( k, value ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public V get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( ( Long ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.get( k ); + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public V remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( ( Long ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.remove( k ); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongObjectMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongObjectMapDecorator.this.containsKey( k ) && + TLongObjectMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongObjectIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long k = it.key(); + final Long key = (k == _map.getNoEntryKey()) ? null : wrapKey( k ); + final V v = it.value(); + return new Map.Entry() { + private V val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals( key ) + && ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public Long getKey() { + return key; + } + + public V getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public V setValue( V value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongObjectMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return _map.containsValue( val ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( ( ( Long ) key ).longValue() ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Long key ) { + return key.longValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TLongObjectMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TLongObjectHashMapDecorator diff --git a/src/gnu/trove/decorator/TLongSetDecorator.java b/src/gnu/trove/decorator/TLongSetDecorator.java new file mode 100644 index 0000000..414df84 --- /dev/null +++ b/src/gnu/trove/decorator/TLongSetDecorator.java @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.set.TLongSet; +import gnu.trove.iterator.TLongIterator; + +import java.io.*; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongSet conform to the java.util.Set API. + * This class simply decorates an underlying TLongSet and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ *

+ * Created: Tue Sep 24 22:08:17 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongSetDecorator extends AbstractSet + implements Set, Externalizable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive set */ + protected TLongSet _set; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongSetDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive set. + * + * @param set the TLongSet to wrap. + */ + public TLongSetDecorator( TLongSet set ) { + super(); + this._set = set; + } + + + /** + * Returns a reference to the set wrapped by this decorator. + * + * @return the wrapped TLongSet instance. + */ + public TLongSet getSet() { + return _set; + } + + + /** + * Inserts a value into the set. + * + * @param value true if the set was modified by the insertion + */ + public boolean add( Long value ) { + return value != null && _set.add( value.longValue() ); + } + + + /** + * Compares this set with another set for equality of their stored + * entries. + * + * @param other an Object value + * @return true if the sets are identical + */ + public boolean equals( Object other ) { + if ( _set.equals( other ) ) { + return true; // comparing two trove sets + } else if ( other instanceof Set ) { + Set that = ( Set ) other; + if ( that.size() != _set.size() ) { + return false; // different sizes, no need to compare + } else { // now we have to do it the hard way + Iterator it = that.iterator(); + for ( int i = that.size(); i-- > 0; ) { + Object val = it.next(); + if ( val instanceof Long ) { + long v = ( ( Long ) val ).longValue(); + if ( _set.contains( v ) ) { + // match, ok to continue + } else { + return false; // no match: we're done + } + } else { + return false; // different type in other set + } + } + return true; // all entries match + } + } else { + return false; + } + } + + + /** + * Empties the set. + */ + public void clear() { + this._set.clear(); + } + + + /** + * Deletes a value from the set. + * + * @param value an Object value + * @return true if the set was modified + */ + public boolean remove( Object value ) { + return value instanceof Long && _set.remove( ( ( Long ) value ).longValue() ); + } + + + /** + * Creates an iterator over the values of the set. + * + * @return an iterator with support for removals in the underlying set + */ + public Iterator iterator() { + return new Iterator() { + private final TLongIterator it = _set.iterator(); + + public Long next() { + return Long.valueOf( it.next() ); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + + /** + * Returns the number of entries in the set. + * + * @return the set's size. + */ + public int size() { + return this._set.size(); + } + + + /** + * Indicates whether set has any entries. + * + * @return true if the set is empty + */ + public boolean isEmpty() { + return this._set.size() == 0; + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean contains( Object o ) { + if ( ! ( o instanceof Long ) ) return false; + return _set.contains( ( ( Long ) o ).longValue() ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SET + _set = ( TLongSet ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SET + out.writeObject( _set ); + } +} // TLongHashSetDecorator diff --git a/src/gnu/trove/decorator/TLongShortMapDecorator.java b/src/gnu/trove/decorator/TLongShortMapDecorator.java new file mode 100644 index 0000000..7410599 --- /dev/null +++ b/src/gnu/trove/decorator/TLongShortMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TLongShortMap; +import gnu.trove.iterator.TLongShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TLongShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TLongShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TLongShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TLongShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TLongShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TLongShortMap to wrap. + */ + public TLongShortMapDecorator( TLongShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TLongShortMap instance. + */ + public TLongShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Short(0) if none was found. + */ + public Short put( Long key, Short value ) { + long k; + short v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + short retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Short remove( Object key ) { + long k; + if ( key != null ) { + if ( key instanceof Long ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TLongShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TLongShortMapDecorator.this.containsKey(k) + && TLongShortMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TLongShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + long ik = it.key(); + final Long key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + short iv = it.value(); + final Short v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Long getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Long key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TLongShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Long && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Long wrapKey( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected long unwrapKey( Object key ) { + return ( ( Long ) key ).longValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TLongShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TLongShortHashMapDecorator diff --git a/src/gnu/trove/decorator/TObjectByteMapDecorator.java b/src/gnu/trove/decorator/TObjectByteMapDecorator.java new file mode 100644 index 0000000..aed94ff --- /dev/null +++ b/src/gnu/trove/decorator/TObjectByteMapDecorator.java @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TObjectByteMap; +import gnu.trove.iterator.TObjectByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TObjectByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TObjectByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TObjectByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** + * the wrapped primitive map + */ + protected TObjectByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TObjectByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TObjectByteMap to wrap. + */ + public TObjectByteMapDecorator( TObjectByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TObjectByteMap instance. + */ + public TObjectByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Byte value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Byte put( K key, Byte value ) { + if ( value == null ) return wrapValue( _map.put( key, _map.getNoEntryValue() ) ); + return wrapValue( _map.put( key, unwrapValue( value ) ) ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + byte v = _map.get( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public Byte remove( Object key ) { + byte v = _map.remove( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TObjectByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TObjectByteMapDecorator.this.containsKey( k ) && + TObjectByteMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TObjectByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + final K key = it.key(); + final Byte v = wrapValue( it.value() ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry && + ( ( Map.Entry ) o ).getKey().equals( key ) && + ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public K getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + K key = ( ( Map.Entry ) o ).getKey(); + _map.remove( key ); + modified = true; + } + return modified; + } + + public boolean addAll(Collection> c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TObjectByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return _map.containsKey( key ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return this._map.size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TObjectByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TObjectByteMapDecorator diff --git a/src/gnu/trove/decorator/TObjectCharMapDecorator.java b/src/gnu/trove/decorator/TObjectCharMapDecorator.java new file mode 100644 index 0000000..aef776f --- /dev/null +++ b/src/gnu/trove/decorator/TObjectCharMapDecorator.java @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TObjectCharMap; +import gnu.trove.iterator.TObjectCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TObjectCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TObjectCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TObjectCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** + * the wrapped primitive map + */ + protected TObjectCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TObjectCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TObjectCharMap to wrap. + */ + public TObjectCharMapDecorator( TObjectCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TObjectCharMap instance. + */ + public TObjectCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Character value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Character put( K key, Character value ) { + if ( value == null ) return wrapValue( _map.put( key, _map.getNoEntryValue() ) ); + return wrapValue( _map.put( key, unwrapValue( value ) ) ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + char v = _map.get( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public Character remove( Object key ) { + char v = _map.remove( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TObjectCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TObjectCharMapDecorator.this.containsKey( k ) && + TObjectCharMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TObjectCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + final K key = it.key(); + final Character v = wrapValue( it.value() ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry && + ( ( Map.Entry ) o ).getKey().equals( key ) && + ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public K getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + K key = ( ( Map.Entry ) o ).getKey(); + _map.remove( key ); + modified = true; + } + return modified; + } + + public boolean addAll(Collection> c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TObjectCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return _map.containsKey( key ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return this._map.size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TObjectCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TObjectCharMapDecorator diff --git a/src/gnu/trove/decorator/TObjectDoubleMapDecorator.java b/src/gnu/trove/decorator/TObjectDoubleMapDecorator.java new file mode 100644 index 0000000..31dd29e --- /dev/null +++ b/src/gnu/trove/decorator/TObjectDoubleMapDecorator.java @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TObjectDoubleMap; +import gnu.trove.iterator.TObjectDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TObjectDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TObjectDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TObjectDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** + * the wrapped primitive map + */ + protected TObjectDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TObjectDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TObjectDoubleMap to wrap. + */ + public TObjectDoubleMapDecorator( TObjectDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TObjectDoubleMap instance. + */ + public TObjectDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Double value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Double put( K key, Double value ) { + if ( value == null ) return wrapValue( _map.put( key, _map.getNoEntryValue() ) ); + return wrapValue( _map.put( key, unwrapValue( value ) ) ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + double v = _map.get( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public Double remove( Object key ) { + double v = _map.remove( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TObjectDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TObjectDoubleMapDecorator.this.containsKey( k ) && + TObjectDoubleMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TObjectDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + final K key = it.key(); + final Double v = wrapValue( it.value() ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry && + ( ( Map.Entry ) o ).getKey().equals( key ) && + ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public K getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + K key = ( ( Map.Entry ) o ).getKey(); + _map.remove( key ); + modified = true; + } + return modified; + } + + public boolean addAll(Collection> c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TObjectDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return _map.containsKey( key ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return this._map.size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TObjectDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TObjectDoubleMapDecorator diff --git a/src/gnu/trove/decorator/TObjectFloatMapDecorator.java b/src/gnu/trove/decorator/TObjectFloatMapDecorator.java new file mode 100644 index 0000000..bcb5a26 --- /dev/null +++ b/src/gnu/trove/decorator/TObjectFloatMapDecorator.java @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TObjectFloatMap; +import gnu.trove.iterator.TObjectFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TObjectFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TObjectFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TObjectFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** + * the wrapped primitive map + */ + protected TObjectFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TObjectFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TObjectFloatMap to wrap. + */ + public TObjectFloatMapDecorator( TObjectFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TObjectFloatMap instance. + */ + public TObjectFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Float value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Float put( K key, Float value ) { + if ( value == null ) return wrapValue( _map.put( key, _map.getNoEntryValue() ) ); + return wrapValue( _map.put( key, unwrapValue( value ) ) ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + float v = _map.get( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public Float remove( Object key ) { + float v = _map.remove( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TObjectFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TObjectFloatMapDecorator.this.containsKey( k ) && + TObjectFloatMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TObjectFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + final K key = it.key(); + final Float v = wrapValue( it.value() ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry && + ( ( Map.Entry ) o ).getKey().equals( key ) && + ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public K getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + K key = ( ( Map.Entry ) o ).getKey(); + _map.remove( key ); + modified = true; + } + return modified; + } + + public boolean addAll(Collection> c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TObjectFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return _map.containsKey( key ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return this._map.size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TObjectFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TObjectFloatMapDecorator diff --git a/src/gnu/trove/decorator/TObjectIntMapDecorator.java b/src/gnu/trove/decorator/TObjectIntMapDecorator.java new file mode 100644 index 0000000..3108d20 --- /dev/null +++ b/src/gnu/trove/decorator/TObjectIntMapDecorator.java @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TObjectIntMap; +import gnu.trove.iterator.TObjectIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TObjectIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TObjectIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TObjectIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** + * the wrapped primitive map + */ + protected TObjectIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TObjectIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TObjectIntMap to wrap. + */ + public TObjectIntMapDecorator( TObjectIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TObjectIntMap instance. + */ + public TObjectIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Integer value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( K key, Integer value ) { + if ( value == null ) return wrapValue( _map.put( key, _map.getNoEntryValue() ) ); + return wrapValue( _map.put( key, unwrapValue( value ) ) ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + int v = _map.get( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public Integer remove( Object key ) { + int v = _map.remove( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TObjectIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TObjectIntMapDecorator.this.containsKey( k ) && + TObjectIntMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TObjectIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + final K key = it.key(); + final Integer v = wrapValue( it.value() ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry && + ( ( Map.Entry ) o ).getKey().equals( key ) && + ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public K getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + K key = ( ( Map.Entry ) o ).getKey(); + _map.remove( key ); + modified = true; + } + return modified; + } + + public boolean addAll(Collection> c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TObjectIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return _map.containsKey( key ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return this._map.size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TObjectIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TObjectIntMapDecorator diff --git a/src/gnu/trove/decorator/TObjectLongMapDecorator.java b/src/gnu/trove/decorator/TObjectLongMapDecorator.java new file mode 100644 index 0000000..89b348e --- /dev/null +++ b/src/gnu/trove/decorator/TObjectLongMapDecorator.java @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TObjectLongMap; +import gnu.trove.iterator.TObjectLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TObjectLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TObjectLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TObjectLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** + * the wrapped primitive map + */ + protected TObjectLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TObjectLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TObjectLongMap to wrap. + */ + public TObjectLongMapDecorator( TObjectLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TObjectLongMap instance. + */ + public TObjectLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Long value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Long put( K key, Long value ) { + if ( value == null ) return wrapValue( _map.put( key, _map.getNoEntryValue() ) ); + return wrapValue( _map.put( key, unwrapValue( value ) ) ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + long v = _map.get( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public Long remove( Object key ) { + long v = _map.remove( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TObjectLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TObjectLongMapDecorator.this.containsKey( k ) && + TObjectLongMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TObjectLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + final K key = it.key(); + final Long v = wrapValue( it.value() ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry && + ( ( Map.Entry ) o ).getKey().equals( key ) && + ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public K getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + K key = ( ( Map.Entry ) o ).getKey(); + _map.remove( key ); + modified = true; + } + return modified; + } + + public boolean addAll(Collection> c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TObjectLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return _map.containsKey( key ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return this._map.size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TObjectLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TObjectLongMapDecorator diff --git a/src/gnu/trove/decorator/TObjectShortMapDecorator.java b/src/gnu/trove/decorator/TObjectShortMapDecorator.java new file mode 100644 index 0000000..3907268 --- /dev/null +++ b/src/gnu/trove/decorator/TObjectShortMapDecorator.java @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TObjectShortMap; +import gnu.trove.iterator.TObjectShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TObjectShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TObjectShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TObjectShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** + * the wrapped primitive map + */ + protected TObjectShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TObjectShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TObjectShortMap to wrap. + */ + public TObjectShortMapDecorator( TObjectShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TObjectShortMap instance. + */ + public TObjectShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Short value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Short put( K key, Short value ) { + if ( value == null ) return wrapValue( _map.put( key, _map.getNoEntryValue() ) ); + return wrapValue( _map.put( key, unwrapValue( value ) ) ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + short v = _map.get( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public Short remove( Object key ) { + short v = _map.remove( key ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TObjectShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TObjectShortMapDecorator.this.containsKey( k ) && + TObjectShortMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TObjectShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + final K key = it.key(); + final Short v = wrapValue( it.value() ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry && + ( ( Map.Entry ) o ).getKey().equals( key ) && + ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public K getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + K key = ( ( Map.Entry ) o ).getKey(); + _map.remove( key ); + modified = true; + } + return modified; + } + + public boolean addAll(Collection> c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TObjectShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return _map.containsKey( key ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return this._map.size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TObjectShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TObjectShortMapDecorator diff --git a/src/gnu/trove/decorator/TShortByteMapDecorator.java b/src/gnu/trove/decorator/TShortByteMapDecorator.java new file mode 100644 index 0000000..13fe97e --- /dev/null +++ b/src/gnu/trove/decorator/TShortByteMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortByteMap; +import gnu.trove.iterator.TShortByteIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortByteMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortByteMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortByteMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortByteMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortByteMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortByteMap to wrap. + */ + public TShortByteMapDecorator( TShortByteMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortByteMap instance. + */ + public TShortByteMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Byte(0) if none was found. + */ + public Byte put( Short key, Byte value ) { + short k; + byte v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + byte retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Byte get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Byte remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + byte v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortByteMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortByteMapDecorator.this.containsKey(k) + && TShortByteMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortByteIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short ik = it.key(); + final Short key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + byte iv = it.value(); + final Byte v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Byte val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Short getKey() { + return key; + } + + public Byte getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Byte setValue( Byte value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortByteMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Byte && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Object key ) { + return ( ( Short ) key ).shortValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Byte wrapValue( byte k ) { + return Byte.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected byte unwrapValue( Object value ) { + return ( ( Byte ) value ).byteValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TShortByteMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TShortByteHashMapDecorator diff --git a/src/gnu/trove/decorator/TShortCharMapDecorator.java b/src/gnu/trove/decorator/TShortCharMapDecorator.java new file mode 100644 index 0000000..69551c3 --- /dev/null +++ b/src/gnu/trove/decorator/TShortCharMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortCharMap; +import gnu.trove.iterator.TShortCharIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortCharMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortCharMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortCharMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortCharMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortCharMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortCharMap to wrap. + */ + public TShortCharMapDecorator( TShortCharMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortCharMap instance. + */ + public TShortCharMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Character(0) if none was found. + */ + public Character put( Short key, Character value ) { + short k; + char v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + char retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Character get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Character remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + char v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortCharMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortCharMapDecorator.this.containsKey(k) + && TShortCharMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortCharIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short ik = it.key(); + final Short key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + char iv = it.value(); + final Character v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Character val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Short getKey() { + return key; + } + + public Character getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Character setValue( Character value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortCharMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Character && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Object key ) { + return ( ( Short ) key ).shortValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Character wrapValue( char k ) { + return Character.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected char unwrapValue( Object value ) { + return ( ( Character ) value ).charValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TShortCharMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TShortCharHashMapDecorator diff --git a/src/gnu/trove/decorator/TShortDoubleMapDecorator.java b/src/gnu/trove/decorator/TShortDoubleMapDecorator.java new file mode 100644 index 0000000..7270ea5 --- /dev/null +++ b/src/gnu/trove/decorator/TShortDoubleMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortDoubleMap; +import gnu.trove.iterator.TShortDoubleIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortDoubleMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortDoubleMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortDoubleMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortDoubleMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortDoubleMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortDoubleMap to wrap. + */ + public TShortDoubleMapDecorator( TShortDoubleMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortDoubleMap instance. + */ + public TShortDoubleMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Double(0) if none was found. + */ + public Double put( Short key, Double value ) { + short k; + double v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + double retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Double get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Double remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + double v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortDoubleMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortDoubleMapDecorator.this.containsKey(k) + && TShortDoubleMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortDoubleIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short ik = it.key(); + final Short key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + double iv = it.value(); + final Double v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Double val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Short getKey() { + return key; + } + + public Double getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Double setValue( Double value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortDoubleMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Double && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Object key ) { + return ( ( Short ) key ).shortValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Double wrapValue( double k ) { + return Double.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected double unwrapValue( Object value ) { + return ( ( Double ) value ).doubleValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TShortDoubleMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TShortDoubleHashMapDecorator diff --git a/src/gnu/trove/decorator/TShortFloatMapDecorator.java b/src/gnu/trove/decorator/TShortFloatMapDecorator.java new file mode 100644 index 0000000..5f3f5f7 --- /dev/null +++ b/src/gnu/trove/decorator/TShortFloatMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortFloatMap; +import gnu.trove.iterator.TShortFloatIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortFloatMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortFloatMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortFloatMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortFloatMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortFloatMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortFloatMap to wrap. + */ + public TShortFloatMapDecorator( TShortFloatMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortFloatMap instance. + */ + public TShortFloatMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Float(0) if none was found. + */ + public Float put( Short key, Float value ) { + short k; + float v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + float retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Float get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Float remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + float v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortFloatMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortFloatMapDecorator.this.containsKey(k) + && TShortFloatMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortFloatIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short ik = it.key(); + final Short key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + float iv = it.value(); + final Float v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Float val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Short getKey() { + return key; + } + + public Float getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Float setValue( Float value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortFloatMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Float && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Object key ) { + return ( ( Short ) key ).shortValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Float wrapValue( float k ) { + return Float.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected float unwrapValue( Object value ) { + return ( ( Float ) value ).floatValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TShortFloatMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TShortFloatHashMapDecorator diff --git a/src/gnu/trove/decorator/TShortIntMapDecorator.java b/src/gnu/trove/decorator/TShortIntMapDecorator.java new file mode 100644 index 0000000..eef18ef --- /dev/null +++ b/src/gnu/trove/decorator/TShortIntMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortIntMap; +import gnu.trove.iterator.TShortIntIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortIntMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortIntMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortIntMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortIntMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortIntMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortIntMap to wrap. + */ + public TShortIntMapDecorator( TShortIntMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortIntMap instance. + */ + public TShortIntMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Integer(0) if none was found. + */ + public Integer put( Short key, Integer value ) { + short k; + int v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + int retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Integer get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Integer remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + int v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortIntMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortIntMapDecorator.this.containsKey(k) + && TShortIntMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortIntIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short ik = it.key(); + final Short key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + int iv = it.value(); + final Integer v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Integer val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Short getKey() { + return key; + } + + public Integer getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Integer setValue( Integer value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortIntMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Integer && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Object key ) { + return ( ( Short ) key ).shortValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Integer wrapValue( int k ) { + return Integer.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected int unwrapValue( Object value ) { + return ( ( Integer ) value ).intValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TShortIntMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TShortIntHashMapDecorator diff --git a/src/gnu/trove/decorator/TShortListDecorator.java b/src/gnu/trove/decorator/TShortListDecorator.java new file mode 100644 index 0000000..9f73f34 --- /dev/null +++ b/src/gnu/trove/decorator/TShortListDecorator.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.list.TShortList; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractList; +import java.util.List; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortList conform to the java.util.List API. + * This class simply decorates an underlying TShortList and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * + * @author Robert D. Eden + */ +public class TShortListDecorator extends AbstractList + implements List, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive list */ + protected TShortList list; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortListDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param list the TShortList to wrap. + */ + public TShortListDecorator( TShortList list ) { + super(); + this.list = list; + } + + + /** + * Returns a reference to the list wrapped by this decorator. + * + * @return the wrapped TShortList instance. + */ + public TShortList getList() { + return list; + } + + + @Override + public int size() { + return list.size(); + } + + + @Override + public Short get( int index ) { + short value = list.get( index ); + if ( value == list.getNoEntryValue() ) return null; + else return Short.valueOf( value ); + } + + + @Override + public Short set( int index, Short value ) { + short previous_value = list.set( index, value ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Short.valueOf( previous_value ); + } + + + @Override + public void add( int index, Short value ) { + list.insert( index, value.shortValue() ); + } + + + @Override + public Short remove( int index ) { + short previous_value = list.removeAt( index ); + if ( previous_value == list.getNoEntryValue() ) return null; + else return Short.valueOf( previous_value ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + list = ( TShortList ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // LIST + out.writeObject( list ); + } + +} diff --git a/src/gnu/trove/decorator/TShortLongMapDecorator.java b/src/gnu/trove/decorator/TShortLongMapDecorator.java new file mode 100644 index 0000000..10d3169 --- /dev/null +++ b/src/gnu/trove/decorator/TShortLongMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortLongMap; +import gnu.trove.iterator.TShortLongIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortLongMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortLongMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortLongMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortLongMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortLongMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortLongMap to wrap. + */ + public TShortLongMapDecorator( TShortLongMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortLongMap instance. + */ + public TShortLongMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Long(0) if none was found. + */ + public Long put( Short key, Long value ) { + short k; + long v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + long retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Long get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Long remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + long v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortLongMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortLongMapDecorator.this.containsKey(k) + && TShortLongMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortLongIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short ik = it.key(); + final Short key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + long iv = it.value(); + final Long v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Long val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Short getKey() { + return key; + } + + public Long getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Long setValue( Long value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortLongMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Long && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Object key ) { + return ( ( Short ) key ).shortValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Long wrapValue( long k ) { + return Long.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected long unwrapValue( Object value ) { + return ( ( Long ) value ).longValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TShortLongMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TShortLongHashMapDecorator diff --git a/src/gnu/trove/decorator/TShortObjectMapDecorator.java b/src/gnu/trove/decorator/TShortObjectMapDecorator.java new file mode 100644 index 0000000..f572f0b --- /dev/null +++ b/src/gnu/trove/decorator/TShortObjectMapDecorator.java @@ -0,0 +1,361 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortObjectMap; +import gnu.trove.iterator.TShortObjectIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortObjectMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortObjectMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortObjectMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortObjectMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortObjectMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortObjectMap to wrap. + */ + public TShortObjectMapDecorator( TShortObjectMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortObjectMap instance. + */ + public TShortObjectMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Short value + * @param value an Object value + * @return the previous value associated with key, + * or null if none was found. + */ + public V put( Short key, V value ) { + short k; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + return _map.put( k, value ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public V get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( ( Short ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.get( k ); + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or Integer(0) if it was not found in the map + */ + public V remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( ( Short ) key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + return _map.remove( k ); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortObjectMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if ( o instanceof Map.Entry ) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortObjectMapDecorator.this.containsKey( k ) && + TShortObjectMapDecorator.this.get( k ).equals( v ); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortObjectIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short k = it.key(); + final Short key = (k == _map.getNoEntryKey()) ? null : wrapKey( k ); + final V v = it.value(); + return new Map.Entry() { + private V val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals( key ) + && ( ( Map.Entry ) o ).getValue().equals( val ); + } + + public Short getKey() { + return key; + } + + public V getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public V setValue( V value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortObjectMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return _map.containsValue( val ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( ( ( Short ) key ).shortValue() ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Short key ) { + return key.shortValue(); + } + + + // Implements Externalizable + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + //noinspection unchecked + _map = ( TShortObjectMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // MAP + out.writeObject( _map ); + } + +} // TShortObjectHashMapDecorator diff --git a/src/gnu/trove/decorator/TShortSetDecorator.java b/src/gnu/trove/decorator/TShortSetDecorator.java new file mode 100644 index 0000000..a8f0971 --- /dev/null +++ b/src/gnu/trove/decorator/TShortSetDecorator.java @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.set.TShortSet; +import gnu.trove.iterator.TShortIterator; + +import java.io.*; +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortSet conform to the java.util.Set API. + * This class simply decorates an underlying TShortSet and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ *

+ * Created: Tue Sep 24 22:08:17 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortSetDecorator extends AbstractSet + implements Set, Externalizable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive set */ + protected TShortSet _set; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortSetDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive set. + * + * @param set the TShortSet to wrap. + */ + public TShortSetDecorator( TShortSet set ) { + super(); + this._set = set; + } + + + /** + * Returns a reference to the set wrapped by this decorator. + * + * @return the wrapped TShortSet instance. + */ + public TShortSet getSet() { + return _set; + } + + + /** + * Inserts a value into the set. + * + * @param value true if the set was modified by the insertion + */ + public boolean add( Short value ) { + return value != null && _set.add( value.shortValue() ); + } + + + /** + * Compares this set with another set for equality of their stored + * entries. + * + * @param other an Object value + * @return true if the sets are identical + */ + public boolean equals( Object other ) { + if ( _set.equals( other ) ) { + return true; // comparing two trove sets + } else if ( other instanceof Set ) { + Set that = ( Set ) other; + if ( that.size() != _set.size() ) { + return false; // different sizes, no need to compare + } else { // now we have to do it the hard way + Iterator it = that.iterator(); + for ( int i = that.size(); i-- > 0; ) { + Object val = it.next(); + if ( val instanceof Short ) { + short v = ( ( Short ) val ).shortValue(); + if ( _set.contains( v ) ) { + // match, ok to continue + } else { + return false; // no match: we're done + } + } else { + return false; // different type in other set + } + } + return true; // all entries match + } + } else { + return false; + } + } + + + /** + * Empties the set. + */ + public void clear() { + this._set.clear(); + } + + + /** + * Deletes a value from the set. + * + * @param value an Object value + * @return true if the set was modified + */ + public boolean remove( Object value ) { + return value instanceof Short && _set.remove( ( ( Short ) value ).shortValue() ); + } + + + /** + * Creates an iterator over the values of the set. + * + * @return an iterator with support for removals in the underlying set + */ + public Iterator iterator() { + return new Iterator() { + private final TShortIterator it = _set.iterator(); + + public Short next() { + return Short.valueOf( it.next() ); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + + /** + * Returns the number of entries in the set. + * + * @return the set's size. + */ + public int size() { + return this._set.size(); + } + + + /** + * Indicates whether set has any entries. + * + * @return true if the set is empty + */ + public boolean isEmpty() { + return this._set.size() == 0; + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean contains( Object o ) { + if ( ! ( o instanceof Short ) ) return false; + return _set.contains( ( ( Short ) o ).shortValue() ); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SET + _set = ( TShortSet ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SET + out.writeObject( _set ); + } +} // TShortHashSetDecorator diff --git a/src/gnu/trove/decorator/TShortShortMapDecorator.java b/src/gnu/trove/decorator/TShortShortMapDecorator.java new file mode 100644 index 0000000..4806752 --- /dev/null +++ b/src/gnu/trove/decorator/TShortShortMapDecorator.java @@ -0,0 +1,409 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.decorator; + +import gnu.trove.map.TShortShortMap; +import gnu.trove.iterator.TShortShortIterator; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Wrapper class to make a TShortShortMap conform to the java.util.Map API. + * This class simply decorates an underlying TShortShortMap and translates the Object-based + * APIs into their Trove primitive analogs. + *

+ * Note that wrapping and unwrapping primitive values is extremely inefficient. If + * possible, users of this class should override the appropriate methods in this class + * and use a table of canonical values. + *

+ * Created: Mon Sep 23 22:07:40 PDT 2002 + * + * @author Eric D. Friedman + * @author Robert D. Eden + * @author Jeff Randall + */ +public class TShortShortMapDecorator extends AbstractMap + implements Map, Externalizable, Cloneable { + + static final long serialVersionUID = 1L; + + /** the wrapped primitive map */ + protected TShortShortMap _map; + + + /** + * FOR EXTERNALIZATION ONLY!! + */ + public TShortShortMapDecorator() {} + + + /** + * Creates a wrapper that decorates the specified primitive map. + * + * @param map the TShortShortMap to wrap. + */ + public TShortShortMapDecorator( TShortShortMap map ) { + super(); + this._map = map; + } + + + /** + * Returns a reference to the map wrapped by this decorator. + * + * @return the wrapped TShortShortMap instance. + */ + public TShortShortMap getMap() { + return _map; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or Short(0) if none was found. + */ + public Short put( Short key, Short value ) { + short k; + short v; + if ( key == null ) { + k = _map.getNoEntryKey(); + } else { + k = unwrapKey( key ); + } + if ( value == null ) { + v = _map.getNoEntryValue(); + } else { + v = unwrapValue( value ); + } + short retval = _map.put( k, v ); + if ( retval == _map.getNoEntryValue() ) { + return null; + } + return wrapValue( retval ); + } + + + /** + * Retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + public Short get( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.get( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Empties the map. + */ + public void clear() { + this._map.clear(); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return the removed value, or null if it was not found in the map + */ + public Short remove( Object key ) { + short k; + if ( key != null ) { + if ( key instanceof Short ) { + k = unwrapKey( key ); + } else { + return null; + } + } else { + k = _map.getNoEntryKey(); + } + short v = _map.remove( k ); + // There may be a false positive since primitive maps + // cannot return null, so we have to do an extra + // check here. + if ( v == _map.getNoEntryValue() ) { + return null; + } else { + return wrapValue( v ); + } + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return _map.size(); + } + + public boolean isEmpty() { + return TShortShortMapDecorator.this.isEmpty(); + } + + @SuppressWarnings("rawtypes") + public boolean contains( Object o ) { + if (o instanceof Map.Entry) { + Object k = ( ( Map.Entry ) o ).getKey(); + Object v = ( ( Map.Entry ) o ).getValue(); + return TShortShortMapDecorator.this.containsKey(k) + && TShortShortMapDecorator.this.get(k).equals(v); + } else { + return false; + } + } + + public Iterator> iterator() { + return new Iterator>() { + private final TShortShortIterator it = _map.iterator(); + + public Map.Entry next() { + it.advance(); + short ik = it.key(); + final Short key = (ik == _map.getNoEntryKey()) ? null : wrapKey( ik ); + short iv = it.value(); + final Short v = (iv == _map.getNoEntryValue()) ? null : wrapValue( iv ); + return new Map.Entry() { + private Short val = v; + + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { + return o instanceof Map.Entry + && ( ( Map.Entry ) o ).getKey().equals(key) + && ( ( Map.Entry ) o ).getValue().equals(val); + } + + public Short getKey() { + return key; + } + + public Short getValue() { + return val; + } + + public int hashCode() { + return key.hashCode() + val.hashCode(); + } + + public Short setValue( Short value ) { + val = value; + return put( key, value ); + } + }; + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + }; + } + + public boolean add( Map.Entry o ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public boolean remove( Object o ) { + boolean modified = false; + if ( contains( o ) ) { + //noinspection unchecked + Short key = ( ( Map.Entry ) o ).getKey(); + _map.remove( unwrapKey( key ) ); + modified = true; + } + return modified; + } + + public boolean addAll( Collection> c ) { + throw new UnsupportedOperationException(); + } + + public void clear() { + TShortShortMapDecorator.this.clear(); + } + }; + } + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue( Object val ) { + return val instanceof Short && _map.containsValue( unwrapValue( val ) ); + } + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + if ( key == null ) return _map.containsKey( _map.getNoEntryKey() ); + return key instanceof Short && _map.containsKey( unwrapKey( key ) ); + } + + + /** + * Returns the number of entries in the map. + * + * @return the map's size. + */ + public int size() { + return this._map.size(); + } + + + /** + * Indicates whether map has any entries. + * + * @return true if the map is empty + */ + public boolean isEmpty() { + return size() == 0; + } + + + /** + * Copies the key/value mappings in map into this map. + * Note that this will be a deep copy, as storage is by + * primitive value. + * + * @param map a Map value + */ + public void putAll( Map map ) { + Iterator> it = + map.entrySet().iterator(); + for ( int i = map.size(); i-- > 0; ) { + Entry e = it.next(); + this.put( e.getKey(), e.getValue() ); + } + } + + + /** + * Wraps a key + * + * @param k key in the underlying map + * @return an Object representation of the key + */ + protected Short wrapKey( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a key + * + * @param key wrapped key + * @return an unwrapped representation of the key + */ + protected short unwrapKey( Object key ) { + return ( ( Short ) key ).shortValue(); + } + + + /** + * Wraps a value + * + * @param k value in the underlying map + * @return an Object representation of the value + */ + protected Short wrapValue( short k ) { + return Short.valueOf( k ); + } + + + /** + * Unwraps a value + * + * @param value wrapped value + * @return an unwrapped representation of the value + */ + protected short unwrapValue( Object value ) { + return ( ( Short ) value ).shortValue(); + } + + + // Implements Externalizable + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // MAP + _map = ( TShortShortMap ) in.readObject(); + } + + + // Implements Externalizable + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte(0); + + // MAP + out.writeObject( _map ); + } + +} // TShortShortHashMapDecorator diff --git a/src/gnu/trove/function/TByteFunction.java b/src/gnu/trove/function/TByteFunction.java new file mode 100644 index 0000000..1fa50ba --- /dev/null +++ b/src/gnu/trove/function/TByteFunction.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for functions that accept and return one byte primitive. + */ +public interface TByteFunction { + /** + * Execute this function with value + * + * @param value a byte input + * @return a byte result + */ + public byte execute( byte value ); +} diff --git a/src/gnu/trove/function/TCharFunction.java b/src/gnu/trove/function/TCharFunction.java new file mode 100644 index 0000000..8f57b66 --- /dev/null +++ b/src/gnu/trove/function/TCharFunction.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for functions that accept and return one char primitive. + */ +public interface TCharFunction { + /** + * Execute this function with value + * + * @param value a char input + * @return a char result + */ + public char execute( char value ); +} diff --git a/src/gnu/trove/function/TDoubleFunction.java b/src/gnu/trove/function/TDoubleFunction.java new file mode 100644 index 0000000..d46f5ae --- /dev/null +++ b/src/gnu/trove/function/TDoubleFunction.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for functions that accept and return one double primitive. + */ +public interface TDoubleFunction { + /** + * Execute this function with value + * + * @param value a double input + * @return a double result + */ + public double execute( double value ); +} diff --git a/src/gnu/trove/function/TFloatFunction.java b/src/gnu/trove/function/TFloatFunction.java new file mode 100644 index 0000000..2b72646 --- /dev/null +++ b/src/gnu/trove/function/TFloatFunction.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for functions that accept and return one float primitive. + */ +public interface TFloatFunction { + /** + * Execute this function with value + * + * @param value a float input + * @return a float result + */ + public float execute( float value ); +} diff --git a/src/gnu/trove/function/TIntFunction.java b/src/gnu/trove/function/TIntFunction.java new file mode 100644 index 0000000..642eabd --- /dev/null +++ b/src/gnu/trove/function/TIntFunction.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for functions that accept and return one int primitive. + */ +public interface TIntFunction { + /** + * Execute this function with value + * + * @param value a int input + * @return a int result + */ + public int execute( int value ); +} diff --git a/src/gnu/trove/function/TLongFunction.java b/src/gnu/trove/function/TLongFunction.java new file mode 100644 index 0000000..64219cb --- /dev/null +++ b/src/gnu/trove/function/TLongFunction.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for functions that accept and return one long primitive. + */ +public interface TLongFunction { + /** + * Execute this function with value + * + * @param value a long input + * @return a long result + */ + public long execute( long value ); +} diff --git a/src/gnu/trove/function/TObjectFunction.java b/src/gnu/trove/function/TObjectFunction.java new file mode 100644 index 0000000..e8873b7 --- /dev/null +++ b/src/gnu/trove/function/TObjectFunction.java @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +/** + * Interface for functions that accept and return one Object reference. + *

+ * Created: Mon Nov 5 22:19:36 2001 + * + * @author Eric D. Friedman + * @version $Id: TObjectFunction.java,v 1.1.2.1 2009/09/06 17:02:19 upholderoftruth Exp $ + */ + +public interface TObjectFunction { + + /** + * Execute this function with value + * + * @param value an Object input + * @return an Object result + */ + public R execute( T value ); +}// TObjectFunction diff --git a/src/gnu/trove/function/TShortFunction.java b/src/gnu/trove/function/TShortFunction.java new file mode 100644 index 0000000..ea3c8de --- /dev/null +++ b/src/gnu/trove/function/TShortFunction.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.function; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for functions that accept and return one short primitive. + */ +public interface TShortFunction { + /** + * Execute this function with value + * + * @param value a short input + * @return a short result + */ + public short execute( short value ); +} diff --git a/src/gnu/trove/impl/Constants.java b/src/gnu/trove/impl/Constants.java new file mode 100644 index 0000000..7a06352 --- /dev/null +++ b/src/gnu/trove/impl/Constants.java @@ -0,0 +1,216 @@ +// //////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// //////////////////////////////////////////////////////////////////////////// +package gnu.trove.impl; + +/** + * Central location for constants needed by various implementations. + */ +public class Constants { + + private static final boolean VERBOSE; + static { + boolean verbose = false; + try { + verbose = System.getProperty( "gnu.trove.verbose", null ) != null; + } + catch( SecurityException ex ) { + // ignore + } + VERBOSE = verbose; + } + + /** the default capacity for new collections */ + public static final int DEFAULT_CAPACITY = 10; + + /** the load above which rehashing occurs. */ + public static final float DEFAULT_LOAD_FACTOR = 0.5f; + + + /** the default value that represents for byte types. */ + public static final byte DEFAULT_BYTE_NO_ENTRY_VALUE; + static { + byte value; + String property = "0"; + try { + property = System.getProperty( "gnu.trove.no_entry.byte", property ); + } + catch( SecurityException ex ) { + // ignore + } + if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Byte.MAX_VALUE; + else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Byte.MIN_VALUE; + else value = Byte.valueOf( property ); + + if ( value > Byte.MAX_VALUE ) value = Byte.MAX_VALUE; + else if ( value < Byte.MIN_VALUE ) value = Byte.MIN_VALUE; + DEFAULT_BYTE_NO_ENTRY_VALUE = value; + if ( VERBOSE ) { + System.out.println( "DEFAULT_BYTE_NO_ENTRY_VALUE: " + + DEFAULT_BYTE_NO_ENTRY_VALUE ); + } + } + + + /** the default value that represents for short types. */ + public static final short DEFAULT_SHORT_NO_ENTRY_VALUE; + static { + short value; + String property = "0"; + try { + property = System.getProperty( "gnu.trove.no_entry.short", property ); + } + catch( SecurityException ex ) { + // ignore + } + if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Short.MAX_VALUE; + else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Short.MIN_VALUE; + else value = Short.valueOf( property ); + + if ( value > Short.MAX_VALUE ) value = Short.MAX_VALUE; + else if ( value < Short.MIN_VALUE ) value = Short.MIN_VALUE; + DEFAULT_SHORT_NO_ENTRY_VALUE = value; + if ( VERBOSE ) { + System.out.println( "DEFAULT_SHORT_NO_ENTRY_VALUE: " + + DEFAULT_SHORT_NO_ENTRY_VALUE ); + } + } + + + /** the default value that represents for char types. */ + public static final char DEFAULT_CHAR_NO_ENTRY_VALUE; + static { + char value; + String property = "\0"; + try { + property = System.getProperty( "gnu.trove.no_entry.char", property ); + } + catch( SecurityException ex ) { + // ignore + } + if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Character.MAX_VALUE; + else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Character.MIN_VALUE; + else value = property.toCharArray()[0]; + + if ( value > Character.MAX_VALUE ) value = Character.MAX_VALUE; + else if ( value < Character.MIN_VALUE ) value = Character.MIN_VALUE; + DEFAULT_CHAR_NO_ENTRY_VALUE = value; + if ( VERBOSE ) { + System.out.println( "DEFAULT_CHAR_NO_ENTRY_VALUE: " + + Integer.valueOf( value ) ); + } + } + + + /** the default value that represents for int types. */ + public static final int DEFAULT_INT_NO_ENTRY_VALUE; + static { + int value; + String property = "0"; + try { + property = System.getProperty( "gnu.trove.no_entry.int", property ); + } + catch( SecurityException ex ) { + // ignore + } + if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Integer.MAX_VALUE; + else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Integer.MIN_VALUE; + else value = Integer.valueOf( property ); + DEFAULT_INT_NO_ENTRY_VALUE = value; + if ( VERBOSE ) { + System.out.println( "DEFAULT_INT_NO_ENTRY_VALUE: " + + DEFAULT_INT_NO_ENTRY_VALUE ); + } + } + + + /** the default value that represents for long types. */ + public static final long DEFAULT_LONG_NO_ENTRY_VALUE; + static { + long value; + String property = "0"; + try { + property = System.getProperty( "gnu.trove.no_entry.long", property ); + } + catch( SecurityException ex ) { + // ignore + } + if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Long.MAX_VALUE; + else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Long.MIN_VALUE; + else value = Long.valueOf( property ); + DEFAULT_LONG_NO_ENTRY_VALUE = value; + if ( VERBOSE ) { + System.out.println( "DEFAULT_LONG_NO_ENTRY_VALUE: " + + DEFAULT_LONG_NO_ENTRY_VALUE ); + } + } + + + /** the default value that represents for float types. */ + public static final float DEFAULT_FLOAT_NO_ENTRY_VALUE; + static { + float value; + String property = "0"; + try { + property = System.getProperty( "gnu.trove.no_entry.float", property ); + } + catch( SecurityException ex ) { + // ignore + } + if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Float.MAX_VALUE; + else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Float.MIN_VALUE; + // Value from Float.MIN_NORMAL (introduced in 1.6) + else if ( "MIN_NORMAL".equalsIgnoreCase( property ) ) value = 0x1.0p-126f; + else if ( "NEGATIVE_INFINITY".equalsIgnoreCase( property ) ) value = Float.NEGATIVE_INFINITY; + else if ( "POSITIVE_INFINITY".equalsIgnoreCase( property ) ) value = Float.POSITIVE_INFINITY; +// else if ( "NaN".equalsIgnoreCase( property ) ) value = Float.NaN; + else value = Float.valueOf( property ); + DEFAULT_FLOAT_NO_ENTRY_VALUE = value; + if ( VERBOSE ) { + System.out.println( "DEFAULT_FLOAT_NO_ENTRY_VALUE: " + + DEFAULT_FLOAT_NO_ENTRY_VALUE ); + } + } + + + /** the default value that represents for double types. */ + public static final double DEFAULT_DOUBLE_NO_ENTRY_VALUE; + static { + double value; + String property = "0"; + try { + property = System.getProperty( "gnu.trove.no_entry.double", property ); + } + catch( SecurityException ex ) { + // ignore + } + if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Double.MAX_VALUE; + else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Double.MIN_VALUE; + // Value from Double.MIN_NORMAL (introduced in 1.6) + else if ( "MIN_NORMAL".equalsIgnoreCase( property ) ) value = 0x1.0p-1022; + else if ( "NEGATIVE_INFINITY".equalsIgnoreCase( property ) ) value = Double.NEGATIVE_INFINITY; + else if ( "POSITIVE_INFINITY".equalsIgnoreCase( property ) ) value = Double.POSITIVE_INFINITY; +// else if ( "NaN".equalsIgnoreCase( property ) ) value = Double.NaN; + else value = Double.valueOf( property ); + DEFAULT_DOUBLE_NO_ENTRY_VALUE = value; + if ( VERBOSE ) { + System.out.println( "DEFAULT_DOUBLE_NO_ENTRY_VALUE: " + + DEFAULT_DOUBLE_NO_ENTRY_VALUE ); + } + } +} diff --git a/src/gnu/trove/impl/HashFunctions.java b/src/gnu/trove/impl/HashFunctions.java new file mode 100644 index 0000000..a7be443 --- /dev/null +++ b/src/gnu/trove/impl/HashFunctions.java @@ -0,0 +1,85 @@ +// Copyright (c) 1999 CERN - European Organization for Nuclear Research. + +// Permission to use, copy, modify, distribute and sell this software and +// its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and that +// both that copyright notice and this permission notice appear in +// supporting documentation. CERN makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without expressed or implied warranty. + +package gnu.trove.impl; + +/** + * Provides various hash functions. + * + * @author wolfgang.hoschek@cern.ch + * @version 1.0, 09/24/99 + */ +public final class HashFunctions { + /** + * Returns a hashcode for the specified value. + * + * @return a hash code value for the specified value. + */ + public static int hash(double value) { + assert !Double.isNaN(value) : "Values of NaN are not supported."; + + long bits = Double.doubleToLongBits(value); + return (int)(bits ^ (bits >>> 32)); + //return (int) Double.doubleToLongBits(value*663608941.737); + //this avoids excessive hashCollisions in the case values are + //of the form (1.0, 2.0, 3.0, ...) + } + + /** + * Returns a hashcode for the specified value. + * + * @return a hash code value for the specified value. + */ + public static int hash(float value) { + assert !Float.isNaN(value) : "Values of NaN are not supported."; + + return Float.floatToIntBits(value*663608941.737f); + // this avoids excessive hashCollisions in the case values are + // of the form (1.0, 2.0, 3.0, ...) + } + + /** + * Returns a hashcode for the specified value. + * + * @return a hash code value for the specified value. + */ + public static int hash(int value) { + return value; + } + + /** + * Returns a hashcode for the specified value. + * + * @return a hash code value for the specified value. + */ + public static int hash(long value) { + return ((int)(value ^ (value >>> 32))); + } + + /** + * Returns a hashcode for the specified object. + * + * @return a hash code value for the specified object. + */ + public static int hash(Object object) { + return object==null ? 0 : object.hashCode(); + } + + + /** + * In profiling, it has been found to be faster to have our own local implementation + * of "ceil" rather than to call to {@link Math#ceil(double)}. + */ + public static int fastCeil( float v ) { + int possible_result = ( int ) v; + if ( v - possible_result > 0 ) possible_result++; + return possible_result; + } +} diff --git a/src/gnu/trove/impl/PrimeFinder.java b/src/gnu/trove/impl/PrimeFinder.java new file mode 100644 index 0000000..11abe57 --- /dev/null +++ b/src/gnu/trove/impl/PrimeFinder.java @@ -0,0 +1,158 @@ +// Copyright (c) 1999 CERN - European Organization for Nuclear Research. + +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear in +// supporting documentation. CERN makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without expressed or implied warranty. +package gnu.trove.impl; + +import java.util.Arrays; + +/* + * Modified for Trove to use the java.util.Arrays sort/search + * algorithms instead of those provided with colt. + */ + +/** + * Used to keep hash table capacities prime numbers. + * Not of interest for users; only for implementors of hashtables. + * + *

Choosing prime numbers as hash table capacities is a good idea + * to keep them working fast, particularly under hash table + * expansions. + * + *

However, JDK 1.2, JGL 3.1 and many other toolkits do nothing to + * keep capacities prime. This class provides efficient means to + * choose prime capacities. + * + *

Choosing a prime is O(log 300) (binary search in a list + * of 300 ints). Memory requirements: 1 KB static memory. + * + * @author wolfgang.hoschek@cern.ch + * @version 1.0, 09/24/99 + */ +public final class PrimeFinder { + /** + * The largest prime this class can generate; currently equal to + * Integer.MAX_VALUE. + */ + public static final int largestPrime = Integer.MAX_VALUE; //yes, it is prime. + + /** + * The prime number list consists of 11 chunks. + * + * Each chunk contains prime numbers. + * + * A chunk starts with a prime P1. The next element is a prime + * P2. P2 is the smallest prime for which holds: P2 >= 2*P1. + * + * The next element is P3, for which the same holds with respect + * to P2, and so on. + * + * Chunks are chosen such that for any desired capacity >= 1000 + * the list includes a prime number <= desired capacity * 1.11. + * + * Therefore, primes can be retrieved which are quite close to any + * desired capacity, which in turn avoids wasting memory. + * + * For example, the list includes + * 1039,1117,1201,1277,1361,1439,1523,1597,1759,1907,2081. + * + * So if you need a prime >= 1040, you will find a prime <= + * 1040*1.11=1154. + * + * Chunks are chosen such that they are optimized for a hashtable + * growthfactor of 2.0; + * + * If your hashtable has such a growthfactor then, after initially + * "rounding to a prime" upon hashtable construction, it will + * later expand to prime capacities such that there exist no + * better primes. + * + * In total these are about 32*10=320 numbers -> 1 KB of static + * memory needed. + * + * If you are stingy, then delete every second or fourth chunk. + */ + + private static final int[] primeCapacities = { + //chunk #0 + largestPrime, + + //chunk #1 + 5,11,23,47,97,197,397,797,1597,3203,6421,12853,25717,51437,102877,205759, + 411527,823117,1646237,3292489,6584983,13169977,26339969,52679969,105359939, + 210719881,421439783,842879579,1685759167, + + //chunk #2 + 433,877,1759,3527,7057,14143,28289,56591,113189,226379,452759,905551,1811107, + 3622219,7244441,14488931,28977863,57955739,115911563,231823147,463646329,927292699, + 1854585413, + + //chunk #3 + 953,1907,3821,7643,15287,30577,61169,122347,244703,489407,978821,1957651,3915341, + 7830701,15661423,31322867,62645741,125291483,250582987,501165979,1002331963, + 2004663929, + + //chunk #4 + 1039,2081,4177,8363,16729,33461,66923,133853,267713,535481,1070981,2141977,4283963, + 8567929,17135863,34271747,68543509,137087021,274174111,548348231,1096696463, + + //chunk #5 + 31,67,137,277,557,1117,2237,4481,8963,17929,35863,71741,143483,286973,573953, + 1147921,2295859,4591721,9183457,18366923,36733847,73467739,146935499,293871013, + 587742049,1175484103, + + //chunk #6 + 599,1201,2411,4831,9677,19373,38747,77509,155027,310081,620171,1240361,2480729, + 4961459,9922933,19845871,39691759,79383533,158767069,317534141,635068283,1270136683, + + //chunk #7 + 311,631,1277,2557,5119,10243,20507,41017,82037,164089,328213,656429,1312867, + 2625761,5251529,10503061,21006137,42012281,84024581,168049163,336098327,672196673, + 1344393353, + + //chunk #8 + 3,7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899, + 701819,1403641,2807303,5614657,11229331,22458671,44917381,89834777,179669557, + 359339171,718678369,1437356741, + + //chunk #9 + 43,89,179,359,719,1439,2879,5779,11579,23159,46327,92657,185323,370661,741337, + 1482707,2965421,5930887,11861791,23723597,47447201,94894427,189788857,379577741, + 759155483,1518310967, + + //chunk #10 + 379,761,1523,3049,6101,12203,24407,48817,97649,195311,390647,781301,1562611, + 3125257,6250537,12501169,25002389,50004791,100009607,200019221,400038451,800076929, + 1600153859 + }; + + static { //initializer + // The above prime numbers are formatted for human readability. + // To find numbers fast, we sort them once and for all. + + Arrays.sort(primeCapacities); + } + + /** + * Returns a prime number which is >= desiredCapacity + * and very close to desiredCapacity (within 11% if + * desiredCapacity >= 1000). + * + * @param desiredCapacity the capacity desired by the user. + * @return the capacity which should be used for a hashtable. + */ + public static final int nextPrime(int desiredCapacity) { + int i = Arrays.binarySearch(primeCapacities, desiredCapacity); + if (i<0) { + // desired capacity not found, choose next prime greater + // than desired capacity + i = -i -1; // remember the semantics of binarySearch... + } + return primeCapacities[i]; + } +} diff --git a/src/gnu/trove/impl/hash/TByteByteHash.java b/src/gnu/trove/impl/hash/TByteByteHash.java new file mode 100644 index 0000000..5e3b02b --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteByteHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte/byte primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TByteByteHash() { + super(); + no_entry_key = ( byte ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( byte ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TByteByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( byte ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TByteByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteByteHash( int initialCapacity, float loadFactor, + byte no_entry_key, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte key ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( byte key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + } +} // TByteByteHash diff --git a/src/gnu/trove/impl/hash/TByteCharHash.java b/src/gnu/trove/impl/hash/TByteCharHash.java new file mode 100644 index 0000000..06c934e --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteCharHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte/char primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TByteCharHash() { + super(); + no_entry_key = ( byte ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( byte ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TByteCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( byte ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TByteCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteCharHash( int initialCapacity, float loadFactor, + byte no_entry_key, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte key ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( byte key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + } +} // TByteCharHash diff --git a/src/gnu/trove/impl/hash/TByteDoubleHash.java b/src/gnu/trove/impl/hash/TByteDoubleHash.java new file mode 100644 index 0000000..bede957 --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteDoubleHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte/double primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TByteDoubleHash() { + super(); + no_entry_key = ( byte ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( byte ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TByteDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( byte ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TByteDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteDoubleHash( int initialCapacity, float loadFactor, + byte no_entry_key, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte key ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( byte key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + } +} // TByteDoubleHash diff --git a/src/gnu/trove/impl/hash/TByteFloatHash.java b/src/gnu/trove/impl/hash/TByteFloatHash.java new file mode 100644 index 0000000..e9a338d --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteFloatHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte/float primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TByteFloatHash() { + super(); + no_entry_key = ( byte ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( byte ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TByteFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( byte ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TByteFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteFloatHash( int initialCapacity, float loadFactor, + byte no_entry_key, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte key ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( byte key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + } +} // TByteFloatHash diff --git a/src/gnu/trove/impl/hash/TByteHash.java b/src/gnu/trove/impl/hash/TByteHash.java new file mode 100644 index 0000000..2f4cbcb --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteHash.java @@ -0,0 +1,334 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.Constants; + +import java.util.Arrays; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte primitives. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + + /** + * Creates a new TByteHash instance with the default + * capacity and load factor. + */ + public TByteHash() { + super(); + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TByteHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteHash( int initialCapacity, float loadFactor, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_value = no_entry_value; + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_value; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param val an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte val ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( val ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == val) + return index; + + return indexRehashed(val, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param val an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + +} // TByteHash diff --git a/src/gnu/trove/impl/hash/TByteIntHash.java b/src/gnu/trove/impl/hash/TByteIntHash.java new file mode 100644 index 0000000..19a7b82 --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteIntHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte/int primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TByteIntHash() { + super(); + no_entry_key = ( byte ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( byte ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TByteIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( byte ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TByteIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteIntHash( int initialCapacity, float loadFactor, + byte no_entry_key, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte key ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( byte key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + } +} // TByteIntHash diff --git a/src/gnu/trove/impl/hash/TByteLongHash.java b/src/gnu/trove/impl/hash/TByteLongHash.java new file mode 100644 index 0000000..b8851ed --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteLongHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte/long primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TByteLongHash() { + super(); + no_entry_key = ( byte ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( byte ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TByteLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( byte ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TByteLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteLongHash( int initialCapacity, float loadFactor, + byte no_entry_key, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte key ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( byte key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + } +} // TByteLongHash diff --git a/src/gnu/trove/impl/hash/TByteShortHash.java b/src/gnu/trove/impl/hash/TByteShortHash.java new file mode 100644 index 0000000..e4845fa --- /dev/null +++ b/src/gnu/trove/impl/hash/TByteShortHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for byte/short primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TByteShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of bytes */ + public transient byte[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TByteShortHash() { + super(); + no_entry_key = ( byte ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TByteShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( byte ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TByteShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( byte ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TByteShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TByteShortHash( int initialCapacity, float loadFactor, + byte no_entry_key, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new byte[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an byte value + * @return a boolean value + */ + public boolean contains( byte val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TByteProcedure procedure ) { + byte[] states = _states; + byte[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an byte value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( byte key ) { + int hash, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(byte key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an byte value + * @return an int value + */ + protected int insertKey( byte val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(byte val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, byte val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( byte key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final byte[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + } +} // TByteShortHash diff --git a/src/gnu/trove/impl/hash/TCharByteHash.java b/src/gnu/trove/impl/hash/TCharByteHash.java new file mode 100644 index 0000000..24928fd --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharByteHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char/byte primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TCharByteHash() { + super(); + no_entry_key = ( char ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( char ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TCharByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( char ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TCharByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharByteHash( int initialCapacity, float loadFactor, + char no_entry_key, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char key ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( char key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + } +} // TCharByteHash diff --git a/src/gnu/trove/impl/hash/TCharCharHash.java b/src/gnu/trove/impl/hash/TCharCharHash.java new file mode 100644 index 0000000..4cf2cbe --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharCharHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char/char primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TCharCharHash() { + super(); + no_entry_key = ( char ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( char ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TCharCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( char ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TCharCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharCharHash( int initialCapacity, float loadFactor, + char no_entry_key, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char key ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( char key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + } +} // TCharCharHash diff --git a/src/gnu/trove/impl/hash/TCharDoubleHash.java b/src/gnu/trove/impl/hash/TCharDoubleHash.java new file mode 100644 index 0000000..3bab6b9 --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharDoubleHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char/double primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TCharDoubleHash() { + super(); + no_entry_key = ( char ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( char ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TCharDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( char ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TCharDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharDoubleHash( int initialCapacity, float loadFactor, + char no_entry_key, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char key ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( char key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + } +} // TCharDoubleHash diff --git a/src/gnu/trove/impl/hash/TCharFloatHash.java b/src/gnu/trove/impl/hash/TCharFloatHash.java new file mode 100644 index 0000000..ac8ce3d --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharFloatHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char/float primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TCharFloatHash() { + super(); + no_entry_key = ( char ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( char ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TCharFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( char ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TCharFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharFloatHash( int initialCapacity, float loadFactor, + char no_entry_key, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char key ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( char key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + } +} // TCharFloatHash diff --git a/src/gnu/trove/impl/hash/TCharHash.java b/src/gnu/trove/impl/hash/TCharHash.java new file mode 100644 index 0000000..e420f5d --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharHash.java @@ -0,0 +1,334 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.Constants; + +import java.util.Arrays; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char primitives. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + + /** + * Creates a new TCharHash instance with the default + * capacity and load factor. + */ + public TCharHash() { + super(); + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TCharHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharHash( int initialCapacity, float loadFactor, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_value = no_entry_value; + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_value; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param val an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char val ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( val ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == val) + return index; + + return indexRehashed(val, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param val an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + +} // TCharHash diff --git a/src/gnu/trove/impl/hash/TCharIntHash.java b/src/gnu/trove/impl/hash/TCharIntHash.java new file mode 100644 index 0000000..342b4e5 --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharIntHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char/int primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TCharIntHash() { + super(); + no_entry_key = ( char ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( char ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TCharIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( char ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TCharIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharIntHash( int initialCapacity, float loadFactor, + char no_entry_key, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char key ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( char key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + } +} // TCharIntHash diff --git a/src/gnu/trove/impl/hash/TCharLongHash.java b/src/gnu/trove/impl/hash/TCharLongHash.java new file mode 100644 index 0000000..e33ae28 --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharLongHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char/long primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TCharLongHash() { + super(); + no_entry_key = ( char ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( char ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TCharLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( char ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TCharLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharLongHash( int initialCapacity, float loadFactor, + char no_entry_key, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char key ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( char key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + } +} // TCharLongHash diff --git a/src/gnu/trove/impl/hash/TCharShortHash.java b/src/gnu/trove/impl/hash/TCharShortHash.java new file mode 100644 index 0000000..13d38f0 --- /dev/null +++ b/src/gnu/trove/impl/hash/TCharShortHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for char/short primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TCharShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of chars */ + public transient char[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TCharShortHash() { + super(); + no_entry_key = ( char ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCharShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( char ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TCharShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( char ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TCharShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TCharShortHash( int initialCapacity, float loadFactor, + char no_entry_key, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new char[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an char value + * @return a boolean value + */ + public boolean contains( char val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TCharProcedure procedure ) { + byte[] states = _states; + char[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an char value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( char key ) { + int hash, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(char key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an char value + * @return an int value + */ + protected int insertKey( char val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(char val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, char val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( char key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final char[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + } +} // TCharShortHash diff --git a/src/gnu/trove/impl/hash/TCustomObjectHash.java b/src/gnu/trove/impl/hash/TCustomObjectHash.java new file mode 100644 index 0000000..912700a --- /dev/null +++ b/src/gnu/trove/impl/hash/TCustomObjectHash.java @@ -0,0 +1,135 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.strategy.HashingStrategy; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + + +/** + * An open addressed hashing implementation for Object types. + * + * @author Rob Eden + * @author Eric D. Friedman + * @author Jeff Randall + * @version $Id: TObjectHash.java,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +@SuppressWarnings( { } ) +abstract public class TCustomObjectHash extends TObjectHash { + static final long serialVersionUID = 8766048185963756400L; + + protected HashingStrategy strategy; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TCustomObjectHash() {} + + + /** + * Creates a new TManualObjectHash instance with the + * default capacity and load factor. + */ + public TCustomObjectHash( HashingStrategy strategy ) { + super(); + + this.strategy = strategy; + } + + + /** + * Creates a new TManualObjectHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TCustomObjectHash( HashingStrategy strategy, int initialCapacity ) { + super( initialCapacity ); + + this.strategy = strategy; + } + + + /** + * Creates a new TManualObjectHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TCustomObjectHash( HashingStrategy strategy, int initialCapacity, + float loadFactor ) { + + super( initialCapacity, loadFactor ); + + this.strategy = strategy; + } + + + @SuppressWarnings("unchecked") + @Override + protected int hash( Object obj ) { + //noinspection unchecked + return strategy.computeHashCode( ( T ) obj ); + } + + @SuppressWarnings("unchecked") + @Override + protected boolean equals( Object one, Object two ) { + //noinspection unchecked + return two != REMOVED && strategy.equals( ( T ) one, ( T ) two ); + } + + + @Override + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + } + + + @SuppressWarnings("unchecked") + @Override + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + //noinspection unchecked + strategy = ( HashingStrategy ) in.readObject(); + } +} // TCustomObjectHash diff --git a/src/gnu/trove/impl/hash/TDoubleByteHash.java b/src/gnu/trove/impl/hash/TDoubleByteHash.java new file mode 100644 index 0000000..7ecf78d --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleByteHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double/byte primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TDoubleByteHash() { + super(); + no_entry_key = ( double ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( double ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TDoubleByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( double ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TDoubleByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleByteHash( int initialCapacity, float loadFactor, + double no_entry_key, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double key ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( double key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + } +} // TDoubleByteHash diff --git a/src/gnu/trove/impl/hash/TDoubleCharHash.java b/src/gnu/trove/impl/hash/TDoubleCharHash.java new file mode 100644 index 0000000..cbff184 --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleCharHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double/char primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TDoubleCharHash() { + super(); + no_entry_key = ( double ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( double ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TDoubleCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( double ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TDoubleCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleCharHash( int initialCapacity, float loadFactor, + double no_entry_key, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double key ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( double key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + } +} // TDoubleCharHash diff --git a/src/gnu/trove/impl/hash/TDoubleDoubleHash.java b/src/gnu/trove/impl/hash/TDoubleDoubleHash.java new file mode 100644 index 0000000..b5ee462 --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleDoubleHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double/double primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TDoubleDoubleHash() { + super(); + no_entry_key = ( double ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( double ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TDoubleDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( double ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TDoubleDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleDoubleHash( int initialCapacity, float loadFactor, + double no_entry_key, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double key ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( double key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + } +} // TDoubleDoubleHash diff --git a/src/gnu/trove/impl/hash/TDoubleFloatHash.java b/src/gnu/trove/impl/hash/TDoubleFloatHash.java new file mode 100644 index 0000000..ca96258 --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleFloatHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double/float primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TDoubleFloatHash() { + super(); + no_entry_key = ( double ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( double ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TDoubleFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( double ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TDoubleFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleFloatHash( int initialCapacity, float loadFactor, + double no_entry_key, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double key ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( double key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + } +} // TDoubleFloatHash diff --git a/src/gnu/trove/impl/hash/TDoubleHash.java b/src/gnu/trove/impl/hash/TDoubleHash.java new file mode 100644 index 0000000..4ce0e3f --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleHash.java @@ -0,0 +1,334 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.Constants; + +import java.util.Arrays; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double primitives. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + + /** + * Creates a new TDoubleHash instance with the default + * capacity and load factor. + */ + public TDoubleHash() { + super(); + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TDoubleHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleHash( int initialCapacity, float loadFactor, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_value = no_entry_value; + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_value; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param val an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double val ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( val ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == val) + return index; + + return indexRehashed(val, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param val an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + +} // TDoubleHash diff --git a/src/gnu/trove/impl/hash/TDoubleIntHash.java b/src/gnu/trove/impl/hash/TDoubleIntHash.java new file mode 100644 index 0000000..0cf0d30 --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleIntHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double/int primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TDoubleIntHash() { + super(); + no_entry_key = ( double ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( double ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TDoubleIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( double ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TDoubleIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleIntHash( int initialCapacity, float loadFactor, + double no_entry_key, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double key ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( double key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + } +} // TDoubleIntHash diff --git a/src/gnu/trove/impl/hash/TDoubleLongHash.java b/src/gnu/trove/impl/hash/TDoubleLongHash.java new file mode 100644 index 0000000..6609ae9 --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleLongHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double/long primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TDoubleLongHash() { + super(); + no_entry_key = ( double ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( double ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TDoubleLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( double ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TDoubleLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleLongHash( int initialCapacity, float loadFactor, + double no_entry_key, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double key ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( double key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + } +} // TDoubleLongHash diff --git a/src/gnu/trove/impl/hash/TDoubleShortHash.java b/src/gnu/trove/impl/hash/TDoubleShortHash.java new file mode 100644 index 0000000..cd8c5eb --- /dev/null +++ b/src/gnu/trove/impl/hash/TDoubleShortHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for double/short primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TDoubleShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of doubles */ + public transient double[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TDoubleShortHash() { + super(); + no_entry_key = ( double ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TDoubleShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( double ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TDoubleShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( double ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TDoubleShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TDoubleShortHash( int initialCapacity, float loadFactor, + double no_entry_key, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new double[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an double value + * @return a boolean value + */ + public boolean contains( double val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an double value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( double key ) { + int hash, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(double key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an double value + * @return an int value + */ + protected int insertKey( double val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(double val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, double val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( double key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final double[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + } +} // TDoubleShortHash diff --git a/src/gnu/trove/impl/hash/TFloatByteHash.java b/src/gnu/trove/impl/hash/TFloatByteHash.java new file mode 100644 index 0000000..194d6a8 --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatByteHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float/byte primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TFloatByteHash() { + super(); + no_entry_key = ( float ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( float ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TFloatByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( float ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TFloatByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatByteHash( int initialCapacity, float loadFactor, + float no_entry_key, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float key ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( float key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + } +} // TFloatByteHash diff --git a/src/gnu/trove/impl/hash/TFloatCharHash.java b/src/gnu/trove/impl/hash/TFloatCharHash.java new file mode 100644 index 0000000..14ef080 --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatCharHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float/char primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TFloatCharHash() { + super(); + no_entry_key = ( float ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( float ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TFloatCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( float ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TFloatCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatCharHash( int initialCapacity, float loadFactor, + float no_entry_key, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float key ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( float key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + } +} // TFloatCharHash diff --git a/src/gnu/trove/impl/hash/TFloatDoubleHash.java b/src/gnu/trove/impl/hash/TFloatDoubleHash.java new file mode 100644 index 0000000..eda4a77 --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatDoubleHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float/double primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TFloatDoubleHash() { + super(); + no_entry_key = ( float ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( float ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TFloatDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( float ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TFloatDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatDoubleHash( int initialCapacity, float loadFactor, + float no_entry_key, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float key ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( float key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + } +} // TFloatDoubleHash diff --git a/src/gnu/trove/impl/hash/TFloatFloatHash.java b/src/gnu/trove/impl/hash/TFloatFloatHash.java new file mode 100644 index 0000000..c68ce9e --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatFloatHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float/float primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TFloatFloatHash() { + super(); + no_entry_key = ( float ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( float ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TFloatFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( float ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TFloatFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatFloatHash( int initialCapacity, float loadFactor, + float no_entry_key, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float key ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( float key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + } +} // TFloatFloatHash diff --git a/src/gnu/trove/impl/hash/TFloatHash.java b/src/gnu/trove/impl/hash/TFloatHash.java new file mode 100644 index 0000000..6811b8c --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatHash.java @@ -0,0 +1,334 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.Constants; + +import java.util.Arrays; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float primitives. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + + /** + * Creates a new TFloatHash instance with the default + * capacity and load factor. + */ + public TFloatHash() { + super(); + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TFloatHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatHash( int initialCapacity, float loadFactor, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_value = no_entry_value; + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_value; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param val an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float val ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( val ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == val) + return index; + + return indexRehashed(val, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param val an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + +} // TFloatHash diff --git a/src/gnu/trove/impl/hash/TFloatIntHash.java b/src/gnu/trove/impl/hash/TFloatIntHash.java new file mode 100644 index 0000000..eb47177 --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatIntHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float/int primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TFloatIntHash() { + super(); + no_entry_key = ( float ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( float ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TFloatIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( float ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TFloatIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatIntHash( int initialCapacity, float loadFactor, + float no_entry_key, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float key ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( float key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + } +} // TFloatIntHash diff --git a/src/gnu/trove/impl/hash/TFloatLongHash.java b/src/gnu/trove/impl/hash/TFloatLongHash.java new file mode 100644 index 0000000..06731b4 --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatLongHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float/long primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TFloatLongHash() { + super(); + no_entry_key = ( float ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( float ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TFloatLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( float ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TFloatLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatLongHash( int initialCapacity, float loadFactor, + float no_entry_key, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float key ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( float key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + } +} // TFloatLongHash diff --git a/src/gnu/trove/impl/hash/TFloatShortHash.java b/src/gnu/trove/impl/hash/TFloatShortHash.java new file mode 100644 index 0000000..941aeab --- /dev/null +++ b/src/gnu/trove/impl/hash/TFloatShortHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for float/short primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TFloatShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of floats */ + public transient float[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TFloatShortHash() { + super(); + no_entry_key = ( float ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TFloatShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( float ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TFloatShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( float ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TFloatShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TFloatShortHash( int initialCapacity, float loadFactor, + float no_entry_key, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new float[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an float value + * @return a boolean value + */ + public boolean contains( float val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TFloatProcedure procedure ) { + byte[] states = _states; + float[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an float value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( float key ) { + int hash, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(float key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an float value + * @return an int value + */ + protected int insertKey( float val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(float val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, float val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( float key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final float[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + } +} // TFloatShortHash diff --git a/src/gnu/trove/impl/hash/THash.java b/src/gnu/trove/impl/hash/THash.java new file mode 100644 index 0000000..dfc5747 --- /dev/null +++ b/src/gnu/trove/impl/hash/THash.java @@ -0,0 +1,429 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.PrimeFinder; + +import java.io.Externalizable; +import java.io.ObjectOutput; +import java.io.IOException; +import java.io.ObjectInput; + + + +/** + * Base class for hashtables that use open addressing to resolve + * collisions. + * + * Created: Wed Nov 28 21:11:16 2001 + * + * @author Eric D. Friedman + * @author Rob Eden (auto-compaction) + * @author Jeff Randall + * + * @version $Id: THash.java,v 1.1.2.4 2010/03/02 00:55:34 robeden Exp $ + */ +abstract public class THash implements Externalizable { + @SuppressWarnings( { } ) + static final long serialVersionUID = -1792948471915530295L; + + /** the load above which rehashing occurs. */ + protected static final float DEFAULT_LOAD_FACTOR = Constants.DEFAULT_LOAD_FACTOR; + + /** + * the default initial capacity for the hash table. This is one + * less than a prime value because one is added to it when + * searching for a prime capacity to account for the free slot + * required by open addressing. Thus, the real default capacity is + * 11. + */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** the current number of occupied slots in the hash. */ + protected transient int _size; + + /** the current number of free slots in the hash. */ + protected transient int _free; + + /** + * Determines how full the internal table can become before + * rehashing is required. This must be a value in the range: 0.0 < + * loadFactor < 1.0. The default value is 0.5, which is about as + * large as you can get in open addressing without hurting + * performance. Cf. Knuth, Volume 3., Chapter 6. + */ + protected float _loadFactor; + + /** + * The maximum number of elements allowed without allocating more + * space. + */ + protected int _maxSize; + + + /** The number of removes that should be performed before an auto-compaction occurs. */ + protected int _autoCompactRemovesRemaining; + + /** + * The auto-compaction factor for the table. + * + * @see #setAutoCompactionFactor + */ + protected float _autoCompactionFactor; + + /** @see #tempDisableAutoCompaction */ + protected transient boolean _autoCompactTemporaryDisable = false; + + + /** + * Creates a new THash instance with the default + * capacity and load factor. + */ + public THash() { + this( DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR ); + } + + + /** + * Creates a new THash instance with a prime capacity + * at or near the specified capacity and with the default load + * factor. + * + * @param initialCapacity an int value + */ + public THash( int initialCapacity ) { + this( initialCapacity, DEFAULT_LOAD_FACTOR ); + } + + + /** + * Creates a new THash instance with a prime capacity + * at or near the minimum needed to hold initialCapacity + * elements with load factor loadFactor without triggering + * a rehash. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public THash( int initialCapacity, float loadFactor ) { + super(); + _loadFactor = loadFactor; + + // Through testing, the load factor (especially the default load factor) has been + // found to be a pretty good starting auto-compaction factor. + _autoCompactionFactor = loadFactor; + + setUp( HashFunctions.fastCeil( initialCapacity / loadFactor ) ); + } + + + /** + * Tells whether this set is currently holding any elements. + * + * @return a boolean value + */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** + * Returns the number of distinct elements in this collection. + * + * @return an int value + */ + public int size() { + return _size; + } + + + /** @return the current physical capacity of the hash table. */ + abstract public int capacity(); + + + /** + * Ensure that this hashtable has sufficient capacity to hold + * desiredCapacity additional elements without + * requiring a rehash. This is a tuning method you can call + * before doing a large insert. + * + * @param desiredCapacity an int value + */ + public void ensureCapacity( int desiredCapacity ) { + if ( desiredCapacity > ( _maxSize - size() ) ) { + rehash( PrimeFinder.nextPrime( Math.max( size() + 1, + HashFunctions.fastCeil( ( desiredCapacity + size() ) / _loadFactor ) + 1 ) ) ); + computeMaxSize( capacity() ); + } + } + + + /** + * Compresses the hashtable to the minimum prime size (as defined + * by PrimeFinder) that will hold all of the elements currently in + * the table. If you have done a lot of remove + * operations and plan to do a lot of queries or insertions or + * iteration, it is a good idea to invoke this method. Doing so + * will accomplish two things: + *

+ *

    + *
  1. You'll free memory allocated to the table but no + * longer needed because of the remove()s.
  2. + *

    + *

  3. You'll get better query/insert/iterator performance + * because there won't be any REMOVED slots to skip + * over when probing for indices in the table.
  4. + *
+ */ + public void compact() { + // need at least one free spot for open addressing + rehash( PrimeFinder.nextPrime( Math.max( _size + 1, + HashFunctions.fastCeil( size() / _loadFactor ) + 1 ) ) ); + computeMaxSize( capacity() ); + + // If auto-compaction is enabled, re-determine the compaction interval + if ( _autoCompactionFactor != 0 ) { + computeNextAutoCompactionAmount( size() ); + } + } + + + /** + * The auto-compaction factor controls whether and when a table performs a + * {@link #compact} automatically after a certain number of remove operations. + * If the value is non-zero, the number of removes that need to occur for + * auto-compaction is the size of table at the time of the previous compaction + * (or the initial capacity) multiplied by this factor. + *

+ * Setting this value to zero will disable auto-compaction. + * + * @param factor a float that indicates the auto-compaction factor + */ + public void setAutoCompactionFactor( float factor ) { + if ( factor < 0 ) { + throw new IllegalArgumentException( "Factor must be >= 0: " + factor ); + } + + _autoCompactionFactor = factor; + } + + + /** + * @see #setAutoCompactionFactor + * + * @return a <float that represents the auto-compaction factor. + */ + public float getAutoCompactionFactor() { + return _autoCompactionFactor; + } + + + /** + * This simply calls {@link #compact compact}. It is included for + * symmetry with other collection classes. Note that the name of this + * method is somewhat misleading (which is why we prefer + * compact) as the load factor may require capacity above + * and beyond the size of this collection. + * + * @see #compact + */ + public final void trimToSize() { + compact(); + } + + + /** + * Delete the record at index. Reduces the size of the + * collection by one. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _size--; + + // If auto-compaction is enabled, see if we need to compact + if ( _autoCompactionFactor != 0 ) { + _autoCompactRemovesRemaining--; + + if ( !_autoCompactTemporaryDisable && _autoCompactRemovesRemaining <= 0 ) { + // Do the compact + // NOTE: this will cause the next compaction interval to be calculated + compact(); + } + } + } + + + /** Empties the collection. */ + public void clear() { + _size = 0; + _free = capacity(); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = PrimeFinder.nextPrime( initialCapacity ); + computeMaxSize( capacity ); + computeNextAutoCompactionAmount( initialCapacity ); + + return capacity; + } + + + /** + * Rehashes the set. + * + * @param newCapacity an int value + */ + protected abstract void rehash( int newCapacity ); + + + /** + * Temporarily disables auto-compaction. MUST be followed by calling + * {@link #reenableAutoCompaction}. + */ + public void tempDisableAutoCompaction() { + _autoCompactTemporaryDisable = true; + } + + + /** + * Re-enable auto-compaction after it was disabled via + * {@link #tempDisableAutoCompaction()}. + * + * @param check_for_compaction True if compaction should be performed if needed + * before returning. If false, no compaction will be + * performed. + */ + public void reenableAutoCompaction( boolean check_for_compaction ) { + _autoCompactTemporaryDisable = false; + + if ( check_for_compaction && _autoCompactRemovesRemaining <= 0 && + _autoCompactionFactor != 0 ) { + + // Do the compact + // NOTE: this will cause the next compaction interval to be calculated + compact(); + } + } + + + /** + * Computes the values of maxSize. There will always be at least + * one free slot required. + * + * @param capacity an int value + */ + protected void computeMaxSize( int capacity ) { + // need at least one free slot for open addressing + _maxSize = Math.min( capacity - 1, (int) ( capacity * _loadFactor ) ); + _free = capacity - _size; // reset the free element count + } + + + /** + * Computes the number of removes that need to happen before the next auto-compaction + * will occur. + * + * @param size an int that sets the auto-compaction limit. + */ + protected void computeNextAutoCompactionAmount( int size ) { + if ( _autoCompactionFactor != 0 ) { + // NOTE: doing the round ourselves has been found to be faster than using + // Math.round. + _autoCompactRemovesRemaining = + (int) ( ( size * _autoCompactionFactor ) + 0.5f ); + } + } + + + /** + * After an insert, this hook is called to adjust the size/free + * values of the set and to perform rehashing if necessary. + * + * @param usedFreeSlot the slot + */ + protected final void postInsertHook( boolean usedFreeSlot ) { + if ( usedFreeSlot ) { + _free--; + } + + // rehash whenever we exhaust the available space in the table + if ( ++_size > _maxSize || _free == 0 ) { + // choose a new capacity suited to the new state of the table + // if we've grown beyond our maximum size, double capacity; + // if we've exhausted the free spots, rehash to the same capacity, + // which will free up any stale removed slots for reuse. + int newCapacity = _size > _maxSize ? PrimeFinder.nextPrime( capacity() << 1 ) : capacity(); + rehash( newCapacity ); + computeMaxSize( capacity() ); + } + } + + + protected int calculateGrownCapacity() { + return capacity() << 1; + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LOAD FACTOR + out.writeFloat( _loadFactor ); + + // AUTO COMPACTION LOAD FACTOR + out.writeFloat( _autoCompactionFactor ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LOAD FACTOR + float old_factor = _loadFactor; + _loadFactor = in.readFloat(); + + // AUTO COMPACTION LOAD FACTOR + _autoCompactionFactor = in.readFloat(); + + // If we change the laod factor from the default, re-setup + if ( old_factor != _loadFactor ) { + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + } +}// THash \ No newline at end of file diff --git a/src/gnu/trove/impl/hash/THashIterator.java b/src/gnu/trove/impl/hash/THashIterator.java new file mode 100644 index 0000000..4898620 --- /dev/null +++ b/src/gnu/trove/impl/hash/THashIterator.java @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.iterator.TIterator; + +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.NoSuchElementException; + + + +/** + * Implements all iterator functions for the hashed object set. + * Subclasses may override objectAtIndex to vary the object + * returned by calls to next() (e.g. for values, and Map.Entry + * objects). + *

+ *

Note that iteration is fastest if you forego the calls to + * hasNext in favor of checking the size of the structure + * yourself and then call next() that many times: + *

+ *

+ * Iterator i = collection.iterator();
+ * for (int size = collection.size(); size-- > 0;) {
+ *   Object o = i.next();
+ * }
+ * 
+ *

+ *

You may, of course, use the hasNext(), next() idiom too if + * you aren't in a performance critical spot.

+ */ +public abstract class THashIterator implements TIterator, Iterator { + + + private final TObjectHash _object_hash; + + /** the data structure this iterator traverses */ + protected final THash _hash; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + + /** + * Create an instance of THashIterator over the values of the TObjectHash + * + * @param hash the object + */ + protected THashIterator( TObjectHash hash ) { + _hash = hash; + _expectedSize = _hash.size(); + _index = _hash.capacity(); + _object_hash = hash; + } + + + /** + * Moves the iterator to the next Object and returns it. + * + * @return an Object value + * @throws ConcurrentModificationException + * if the structure + * was changed using a method that isn't on this iterator. + * @throws NoSuchElementException if this is called on an + * exhausted iterator. + */ + public V next() { + moveToNextIndex(); + return objectAtIndex( _index ); + } + + + /** + * Returns true if the iterator can be advanced past its current + * location. + * + * @return a boolean value + */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + + /** + * Removes the last entry returned by the iterator. + * Invoking this method more than once for a single entry + * will leave the underlying data structure in a confused + * state. + */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + _hash.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = _object_hash._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || set[i] == TObjectHash.REMOVED ) ) { + ; + } + return i; + } + + + /** + * Returns the object at the specified index. Subclasses should + * implement this to return the appropriate object for the given + * index. + * + * @param index the index of the value to return. + * @return an Object value + */ + abstract protected V objectAtIndex( int index ); +} // THashIterator diff --git a/src/gnu/trove/impl/hash/THashPrimitiveIterator.java b/src/gnu/trove/impl/hash/THashPrimitiveIterator.java new file mode 100644 index 0000000..9e7ecb2 --- /dev/null +++ b/src/gnu/trove/impl/hash/THashPrimitiveIterator.java @@ -0,0 +1,143 @@ +// //////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// //////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.iterator.TPrimitiveIterator; + +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; + + +/** + * Implements all iterator functions for the hashed object set. + * Subclasses may override objectAtIndex to vary the object + * returned by calls to next() (e.g. for values, and Map.Entry + * objects). + *

+ *

Note that iteration is fastest if you forego the calls to + * hasNext in favor of checking the size of the structure + * yourself and then call next() that many times: + *

+ *

+ * Iterator i = collection.iterator();
+ * for (int size = collection.size(); size-- > 0;) {
+ *   Object o = i.next();
+ * }
+ * 
+ *

+ *

You may, of course, use the hasNext(), next() idiom too if + * you aren't in a performance critical spot.

+ */ +public abstract class THashPrimitiveIterator implements TPrimitiveIterator { + + /** the data structure this iterator traverses */ + protected final TPrimitiveHash _hash; + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + /** the index used for iteration. */ + protected int _index; + + + /** + * Creates a TPrimitiveIterator for the specified collection. + * + * @param hash the TPrimitiveHash we want to iterate over. + */ + public THashPrimitiveIterator( TPrimitiveHash hash ) { + _hash = hash; + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying collection's + * size has been modified since the iterator was created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + byte[] states = _hash._states; + int i = _index; + while ( i-- > 0 && ( states[i] != TPrimitiveHash.FULL ) ) { + ; + } + return i; + } + + + /** + * Returns true if the iterator can be advanced past its current + * location. + * + * @return a boolean value + */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + + /** + * Removes the last entry returned by the iterator. + * Invoking this method more than once for a single entry + * will leave the underlying data structure in a confused + * state. + */ + public void remove() { + if (_expectedSize != _hash.size()) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + _hash.removeAt(_index); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + +} // TPrimitiveIterator \ No newline at end of file diff --git a/src/gnu/trove/impl/hash/TIntByteHash.java b/src/gnu/trove/impl/hash/TIntByteHash.java new file mode 100644 index 0000000..4c8b758 --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntByteHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int/byte primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TIntByteHash() { + super(); + no_entry_key = ( int ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( int ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TIntByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( int ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TIntByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntByteHash( int initialCapacity, float loadFactor, + int no_entry_key, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int key ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( int key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + } +} // TIntByteHash diff --git a/src/gnu/trove/impl/hash/TIntCharHash.java b/src/gnu/trove/impl/hash/TIntCharHash.java new file mode 100644 index 0000000..d5381a5 --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntCharHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int/char primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TIntCharHash() { + super(); + no_entry_key = ( int ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( int ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TIntCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( int ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TIntCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntCharHash( int initialCapacity, float loadFactor, + int no_entry_key, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int key ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( int key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + } +} // TIntCharHash diff --git a/src/gnu/trove/impl/hash/TIntDoubleHash.java b/src/gnu/trove/impl/hash/TIntDoubleHash.java new file mode 100644 index 0000000..0425b85 --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntDoubleHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int/double primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TIntDoubleHash() { + super(); + no_entry_key = ( int ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( int ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TIntDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( int ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TIntDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntDoubleHash( int initialCapacity, float loadFactor, + int no_entry_key, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int key ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( int key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + } +} // TIntDoubleHash diff --git a/src/gnu/trove/impl/hash/TIntFloatHash.java b/src/gnu/trove/impl/hash/TIntFloatHash.java new file mode 100644 index 0000000..9d9a9e0 --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntFloatHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int/float primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TIntFloatHash() { + super(); + no_entry_key = ( int ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( int ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TIntFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( int ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TIntFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntFloatHash( int initialCapacity, float loadFactor, + int no_entry_key, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int key ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( int key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + } +} // TIntFloatHash diff --git a/src/gnu/trove/impl/hash/TIntHash.java b/src/gnu/trove/impl/hash/TIntHash.java new file mode 100644 index 0000000..fd423c2 --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntHash.java @@ -0,0 +1,334 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.Constants; + +import java.util.Arrays; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int primitives. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + + /** + * Creates a new TIntHash instance with the default + * capacity and load factor. + */ + public TIntHash() { + super(); + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TIntHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntHash( int initialCapacity, float loadFactor, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_value = no_entry_value; + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_value; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param val an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int val ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( val ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == val) + return index; + + return indexRehashed(val, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param val an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + +} // TIntHash diff --git a/src/gnu/trove/impl/hash/TIntIntHash.java b/src/gnu/trove/impl/hash/TIntIntHash.java new file mode 100644 index 0000000..1257bae --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntIntHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int/int primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TIntIntHash() { + super(); + no_entry_key = ( int ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( int ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TIntIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( int ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TIntIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntIntHash( int initialCapacity, float loadFactor, + int no_entry_key, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int key ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( int key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + } +} // TIntIntHash diff --git a/src/gnu/trove/impl/hash/TIntLongHash.java b/src/gnu/trove/impl/hash/TIntLongHash.java new file mode 100644 index 0000000..d4160f0 --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntLongHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int/long primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TIntLongHash() { + super(); + no_entry_key = ( int ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( int ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TIntLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( int ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TIntLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntLongHash( int initialCapacity, float loadFactor, + int no_entry_key, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int key ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( int key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + } +} // TIntLongHash diff --git a/src/gnu/trove/impl/hash/TIntShortHash.java b/src/gnu/trove/impl/hash/TIntShortHash.java new file mode 100644 index 0000000..ab65a9d --- /dev/null +++ b/src/gnu/trove/impl/hash/TIntShortHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for int/short primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TIntShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of ints */ + public transient int[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TIntShortHash() { + super(); + no_entry_key = ( int ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TIntShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( int ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TIntShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( int ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TIntShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TIntShortHash( int initialCapacity, float loadFactor, + int no_entry_key, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new int[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an int value + * @return a boolean value + */ + public boolean contains( int val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TIntProcedure procedure ) { + byte[] states = _states; + int[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an int value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( int key ) { + int hash, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(int key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an int value + * @return an int value + */ + protected int insertKey( int val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(int val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, int val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( int key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final int[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + } +} // TIntShortHash diff --git a/src/gnu/trove/impl/hash/TLongByteHash.java b/src/gnu/trove/impl/hash/TLongByteHash.java new file mode 100644 index 0000000..f4edac9 --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongByteHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long/byte primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TLongByteHash() { + super(); + no_entry_key = ( long ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( long ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TLongByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( long ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TLongByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongByteHash( int initialCapacity, float loadFactor, + long no_entry_key, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long key ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( long key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + } +} // TLongByteHash diff --git a/src/gnu/trove/impl/hash/TLongCharHash.java b/src/gnu/trove/impl/hash/TLongCharHash.java new file mode 100644 index 0000000..ceca428 --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongCharHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long/char primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TLongCharHash() { + super(); + no_entry_key = ( long ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( long ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TLongCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( long ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TLongCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongCharHash( int initialCapacity, float loadFactor, + long no_entry_key, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long key ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( long key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + } +} // TLongCharHash diff --git a/src/gnu/trove/impl/hash/TLongDoubleHash.java b/src/gnu/trove/impl/hash/TLongDoubleHash.java new file mode 100644 index 0000000..b71bc9a --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongDoubleHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long/double primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TLongDoubleHash() { + super(); + no_entry_key = ( long ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( long ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TLongDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( long ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TLongDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongDoubleHash( int initialCapacity, float loadFactor, + long no_entry_key, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long key ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( long key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + } +} // TLongDoubleHash diff --git a/src/gnu/trove/impl/hash/TLongFloatHash.java b/src/gnu/trove/impl/hash/TLongFloatHash.java new file mode 100644 index 0000000..84918a2 --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongFloatHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long/float primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TLongFloatHash() { + super(); + no_entry_key = ( long ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( long ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TLongFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( long ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TLongFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongFloatHash( int initialCapacity, float loadFactor, + long no_entry_key, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long key ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( long key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + } +} // TLongFloatHash diff --git a/src/gnu/trove/impl/hash/TLongHash.java b/src/gnu/trove/impl/hash/TLongHash.java new file mode 100644 index 0000000..413ac4d --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongHash.java @@ -0,0 +1,334 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.Constants; + +import java.util.Arrays; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long primitives. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + + /** + * Creates a new TLongHash instance with the default + * capacity and load factor. + */ + public TLongHash() { + super(); + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TLongHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongHash( int initialCapacity, float loadFactor, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_value = no_entry_value; + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_value; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param val an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long val ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( val ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == val) + return index; + + return indexRehashed(val, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param val an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + +} // TLongHash diff --git a/src/gnu/trove/impl/hash/TLongIntHash.java b/src/gnu/trove/impl/hash/TLongIntHash.java new file mode 100644 index 0000000..b85b8e1 --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongIntHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long/int primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TLongIntHash() { + super(); + no_entry_key = ( long ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( long ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TLongIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( long ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TLongIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongIntHash( int initialCapacity, float loadFactor, + long no_entry_key, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long key ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( long key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + } +} // TLongIntHash diff --git a/src/gnu/trove/impl/hash/TLongLongHash.java b/src/gnu/trove/impl/hash/TLongLongHash.java new file mode 100644 index 0000000..76e58b2 --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongLongHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long/long primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TLongLongHash() { + super(); + no_entry_key = ( long ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( long ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TLongLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( long ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TLongLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongLongHash( int initialCapacity, float loadFactor, + long no_entry_key, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long key ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( long key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + } +} // TLongLongHash diff --git a/src/gnu/trove/impl/hash/TLongShortHash.java b/src/gnu/trove/impl/hash/TLongShortHash.java new file mode 100644 index 0000000..2e29079 --- /dev/null +++ b/src/gnu/trove/impl/hash/TLongShortHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for long/short primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TLongShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of longs */ + public transient long[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TLongShortHash() { + super(); + no_entry_key = ( long ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TLongShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( long ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TLongShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( long ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TLongShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TLongShortHash( int initialCapacity, float loadFactor, + long no_entry_key, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new long[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an long value + * @return a boolean value + */ + public boolean contains( long val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TLongProcedure procedure ) { + byte[] states = _states; + long[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an long value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( long key ) { + int hash, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(long key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an long value + * @return an int value + */ + protected int insertKey( long val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(long val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, long val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( long key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final long[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + } +} // TLongShortHash diff --git a/src/gnu/trove/impl/hash/TObjectHash.java b/src/gnu/trove/impl/hash/TObjectHash.java new file mode 100644 index 0000000..54e905f --- /dev/null +++ b/src/gnu/trove/impl/hash/TObjectHash.java @@ -0,0 +1,619 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TObjectProcedure; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + + +/** + * An open addressed hashing implementation for Object types. + *

+ * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: TObjectHash.java,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TObjectHash extends THash { + + @SuppressWarnings({}) + static final long serialVersionUID = -3461112548087185871L; + + + /** + * the set of Objects + */ + public transient Object[] _set; + + public static final Object REMOVED = new Object(), FREE = new Object(); + + /** + * Indicates whether the last insertKey() call used a FREE slot. This field + * should be inspected right after call insertKey() + */ + protected boolean consumeFreeSlot; + + + /** + * Creates a new TObjectHash instance with the + * default capacity and load factor. + */ + public TObjectHash() { + super(); + } + + + /** + * Creates a new TObjectHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TObjectHash(int initialCapacity) { + super(initialCapacity); + } + + + /** + * Creates a new TObjectHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TObjectHash(int initialCapacity, float loadFactor) { + super(initialCapacity, loadFactor); + } + + + public int capacity() { + return _set.length; + } + + + protected void removeAt(int index) { + _set[index] = REMOVED; + super.removeAt(index); + } + + + /** + * initializes the Object set of this hash table. + * + * @param initialCapacity an int value + * @return an int value + */ + public int setUp(int initialCapacity) { + int capacity; + + capacity = super.setUp(initialCapacity); + _set = new Object[capacity]; + Arrays.fill(_set, FREE); + return capacity; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEach(TObjectProcedure procedure) { + Object[] set = _set; + for (int i = set.length; i-- > 0;) { + if (set[i] != FREE + && set[i] != REMOVED + && !procedure.execute((T) set[i])) { + return false; + } + } + return true; + } + + + /** + * Searches the set for obj + * + * @param obj an Object value + * @return a boolean value + */ + @SuppressWarnings({}) + public boolean contains(Object obj) { + return index(obj) >= 0; + } + + + /** + * Locates the index of obj. + * + * @param obj an Object value + * @return the index of obj or -1 if it isn't in the set. + */ + protected int index(Object obj) { + if (obj == null) + return indexForNull(); + + // From here on we know obj to be non-null + final int hash = hash(obj) & 0x7fffffff; + int index = hash % _set.length; + Object cur = _set[index]; + + + if (cur == FREE) { + return -1; + } + + if (cur == obj || equals(obj, cur)) { + return index; + } + + return indexRehashed(obj, index, hash, cur); + } + + /** + * Locates the index of non-null obj. + * + * @param obj target key, know to be non-null + * @param index we start from + * @param hash + * @param cur + * @return + */ + private int indexRehashed(Object obj, int index, int hash, Object cur) { + final Object[] set = _set; + final int length = set.length; + + // NOTE: here it has to be REMOVED or FULL (some user-given value) + // see Knuth, p. 529 + int probe = 1 + (hash % (length - 2)); + + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + cur = set[index]; + // + if (cur == FREE) + return -1; + + // + if ((cur == obj || equals(obj, cur))) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index null. + *

+ * null specific loop exploiting several properties to simplify the iteration logic + * - the null value hashes to 0 we so we can iterate from the beginning. + * - the probe value is 1 for this case + * - object identity can be used to match this case + *

+ * --> this result a simpler loop + * + * @return + */ + private int indexForNull() { + int index = 0; + for (Object o : _set) { + if (o == null) + return index; + + if (o == FREE) + return -1; + + index++; + } + + return -1; + } + + /** + * Alias introduced to avoid breaking the API. The new method name insertKey() reflects the + * changes made to the logic. + * + * @param obj + * @return + * @deprecated use {@link #insertKey} instead + */ + @Deprecated + protected int insertionIndex(T obj) { + return insertKey(obj); + } + + /** + * Locates the index at which key can be inserted. if + * there is already a value equal()ing key in the set, + * returns that value's index as -index - 1. + *

+ * If a slot is found the value is inserted. When a FREE slot is used the consumeFreeSlot field is + * set to true. This field should be used in the method invoking insertKey() to pass to postInsertHook() + * + * @param key an Object value + * @return the index of a FREE slot at which key can be inserted + * or, if key is already stored in the hash, the negative value of + * that index, minus 1: -index -1. + */ + protected int insertKey(T key) { + consumeFreeSlot = false; + + if (key == null) + return insertKeyForNull(); + + final int hash = hash(key) & 0x7fffffff; + int index = hash % _set.length; + Object cur = _set[index]; + + if (cur == FREE) { + consumeFreeSlot = true; + _set[index] = key; // insert value + return index; // empty, all done + } + + if (cur == key || equals(key, cur)) { + return -index - 1; // already stored + } + + return insertKeyRehash(key, index, hash, cur); + } + + /** + * Looks for a slot using double hashing for a non-null key values and inserts the value + * in the slot + * + * @param key non-null key value + * @param index natural index + * @param hash + * @param cur value of first matched slot + * @return + */ + private int insertKeyRehash(T key, int index, int hash, Object cur) { + final Object[] set = _set; + final int length = set.length; + // already FULL or REMOVED, must probe + // compute the double hash + final int probe = 1 + (hash % (length - 2)); + + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (cur == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + cur = set[index]; + + // A FREE slot stops the search + if (cur == FREE) { + if (firstRemoved != -1) { + _set[firstRemoved] = key; + return firstRemoved; + } else { + consumeFreeSlot = true; + _set[index] = key; // insert value + return index; + } + } + + if (cur == key || equals(key, cur)) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + _set[firstRemoved] = key; + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + /** + * Looks for a slot using double hashing for a null key value and inserts the value. + *

+ * null specific loop exploiting several properties to simplify the iteration logic + * - the null value hashes to 0 we so we can iterate from the beginning. + * - the probe value is 1 for this case + * - object identity can be used to match this case + * + * @return + */ + private int insertKeyForNull() { + int index = 0; + int firstRemoved = -1; + + // Look for a slot containing the 'null' value as key + for (Object o : _set) { + // Locate first removed + if (o == REMOVED && firstRemoved == -1) + firstRemoved = index; + + if (o == FREE) { + if (firstRemoved != -1) { + _set[firstRemoved] = null; + return firstRemoved; + } else { + consumeFreeSlot = true; + _set[index] = null; // insert value + return index; + } + } + + if (o == null) { + return -index - 1; + } + + index++; + } + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + _set[firstRemoved] = null; + return firstRemoved; + } + + // We scanned the entire key set and found nothing, is set full? + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("Could not find insertion index for null key. Key set full!?!!"); + } + + + /** + * Convenience methods for subclasses to use in throwing exceptions about + * badly behaved user objects employed as keys. We have to throw an + * IllegalArgumentException with a rather verbose message telling the + * user that they need to fix their object implementation to conform + * to the general contract for java.lang.Object. + * + * + * @param o1 the first of the equal elements with unequal hash codes. + * @param o2 the second of the equal elements with unequal hash codes. + * @throws IllegalArgumentException the whole point of this method. + */ + protected final void throwObjectContractViolation(Object o1, Object o2) + throws IllegalArgumentException { + throw buildObjectContractViolation(o1, o2, ""); + } + + /** + * Convenience methods for subclasses to use in throwing exceptions about + * badly behaved user objects employed as keys. We have to throw an + * IllegalArgumentException with a rather verbose message telling the + * user that they need to fix their object implementation to conform + * to the general contract for java.lang.Object. + * + * + * @param o1 the first of the equal elements with unequal hash codes. + * @param o2 the second of the equal elements with unequal hash codes. + * @param size + *@param oldSize + * @param oldKeys @throws IllegalArgumentException the whole point of this method. + */ + protected final void throwObjectContractViolation(Object o1, Object o2, int size, int oldSize, Object[] oldKeys) + throws IllegalArgumentException { + String extra = dumpExtraInfo(o1, o2, size(), oldSize, oldKeys); + + + throw buildObjectContractViolation(o1, o2, extra); + } + + /** + * Convenience methods for subclasses to use in throwing exceptions about + * badly behaved user objects employed as keys. We have to throw an + * IllegalArgumentException with a rather verbose message telling the + * user that they need to fix their object implementation to conform + * to the general contract for java.lang.Object. + * + * + * @param o1 the first of the equal elements with unequal hash codes. + * @param o2 the second of the equal elements with unequal hash codes. + * @throws IllegalArgumentException the whole point of this method. + */ + protected final IllegalArgumentException buildObjectContractViolation(Object o1, Object o2, String extra ) { + return new IllegalArgumentException("Equal objects must have equal hashcodes. " + + "During rehashing, Trove discovered that the following two objects claim " + + "to be equal (as in java.lang.Object.equals()) but their hashCodes (or " + + "those calculated by your TObjectHashingStrategy) are not equal." + + "This violates the general contract of java.lang.Object.hashCode(). See " + + "bullet point two in that method's documentation. object #1 =" + objectInfo(o1) + + "; object #2 =" + objectInfo(o2) + "\n" + extra); + } + + + protected boolean equals(Object notnull, Object two) { + if (two == null || two == REMOVED) + return false; + + return notnull.equals(two); + } + + protected int hash(Object notnull) { + return notnull.hashCode(); + } + + protected static String reportPotentialConcurrentMod(int newSize, int oldSize) { + // Note that we would not be able to detect concurrent paired of put()-remove() + // operations with this simple check + if (newSize != oldSize) + return "[Warning] apparent concurrent modification of the key set. " + + "Size before and after rehash() do not match " + oldSize + " vs " + newSize; + + return ""; + } + + /** + * + * @param newVal the key being inserted + * @param oldVal the key already stored at that position + * @param currentSize size of the key set during rehashing + * @param oldSize size of the key set before rehashing + * @param oldKeys the old key set + */ + protected String dumpExtraInfo(Object newVal, Object oldVal, int currentSize, int oldSize, Object[] oldKeys) { + StringBuilder b = new StringBuilder(); + // + b.append(dumpKeyTypes(newVal, oldVal)); + + b.append(reportPotentialConcurrentMod(currentSize, oldSize)); + b.append(detectKeyLoss(oldKeys, oldSize)); + + // Is de same object already present? Double insert? + if (newVal == oldVal) { + b.append("Inserting same object twice, rehashing bug. Object= ").append(oldVal); + } + + return b.toString(); + } + + /** + * Detect inconsistent hashCode() and/or equals() methods + * + * @param keys + * @param oldSize + * @return + */ + private static String detectKeyLoss(Object[] keys, int oldSize) { + StringBuilder buf = new StringBuilder(); + Set k = makeKeySet(keys); + if (k.size() != oldSize) { + buf.append("\nhashCode() and/or equals() have inconsistent implementation"); + buf.append("\nKey set lost entries, now got ").append(k.size()).append(" instead of ").append(oldSize); + buf.append(". This can manifest itself as an apparent duplicate key."); + } + + return buf.toString(); + } + + private static Set makeKeySet(Object[] keys) { + Set types = new HashSet(); + for (Object o : keys) { + if (o != FREE && o != REMOVED) { + types.add(o); + } + } + + return types; + } + + private static String equalsSymmetryInfo(Object a, Object b) { + StringBuilder buf = new StringBuilder(); + if (a == b) { + return "a == b"; + } + + if (a.getClass() != b.getClass()) { + buf.append("Class of objects differ a=").append(a.getClass()).append(" vs b=").append(b.getClass()); + + boolean aEb = a.equals(b); + boolean bEa = b.equals(a); + if (aEb != bEa) { + buf.append("\nequals() of a or b object are asymmetric"); + buf.append("\na.equals(b) =").append(aEb); + buf.append("\nb.equals(a) =").append(bEa); + } + } + + return buf.toString(); + } + + protected static String objectInfo(Object o) { + return (o == null ? "class null" : o.getClass()) + " id= " + System.identityHashCode(o) + + " hashCode= " + (o == null ? 0 : o.hashCode()) + " toString= " + String.valueOf(o); + } + + private String dumpKeyTypes(Object newVal, Object oldVal) { + StringBuilder buf = new StringBuilder(); + Set> types = new HashSet>(); + for (Object o : _set) { + if (o != FREE && o != REMOVED) { + if (o != null) + types.add(o.getClass()); + else + types.add(null); + } + } + + if (types.size() > 1) { + buf.append("\nMore than one type used for keys. Watch out for asymmetric equals(). " + + "Read about the 'Liskov substitution principle' and the implications for equals() in java."); + + buf.append("\nKey types: ").append(types); + buf.append(equalsSymmetryInfo(newVal, oldVal)); + } + + return buf.toString(); + } + + + @Override + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // SUPER + super.writeExternal(out); + } + + + @Override + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal(in); + } +} // TObjectHash diff --git a/src/gnu/trove/impl/hash/TPrimitiveHash.java b/src/gnu/trove/impl/hash/TPrimitiveHash.java new file mode 100644 index 0000000..1e03196 --- /dev/null +++ b/src/gnu/trove/impl/hash/TPrimitiveHash.java @@ -0,0 +1,137 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.impl.HashFunctions; + + + +/** + * The base class for hashtables of primitive values. Since there is + * no notion of object equality for primitives, it isn't possible to + * use a `REMOVED' object to track deletions in an open-addressed table. + * So, we have to resort to using a parallel `bookkeeping' array of bytes, + * in which flags can be set to indicate that a particular slot in the + * hash table is FREE, FULL, or REMOVED. + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: TPrimitiveHash.java,v 1.1.2.6 2010/03/01 23:39:07 robeden Exp $ + */ +abstract public class TPrimitiveHash extends THash { + @SuppressWarnings( { } ) + static final long serialVersionUID = 1L; + + /** + * flags indicating whether each position in the hash is + * FREE, FULL, or REMOVED + */ + public transient byte[] _states; + + /* constants used for state flags */ + + /** flag indicating that a slot in the hashtable is available */ + public static final byte FREE = 0; + + /** flag indicating that a slot in the hashtable is occupied */ + public static final byte FULL = 1; + + /** + * flag indicating that the value of a slot in the hashtable + * was deleted + */ + public static final byte REMOVED = 2; + + + /** + * Creates a new THash instance with the default + * capacity and load factor. + */ + public TPrimitiveHash() { + super(); + } + + + /** + * Creates a new TPrimitiveHash instance with a prime + * capacity at or near the specified capacity and with the default + * load factor. + * + * @param initialCapacity an int value + */ + public TPrimitiveHash( int initialCapacity ) { + this( initialCapacity, DEFAULT_LOAD_FACTOR ); + } + + + /** + * Creates a new TPrimitiveHash instance with a prime + * capacity at or near the minimum needed to hold + * initialCapacity elements with load factor + * loadFactor without triggering a rehash. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TPrimitiveHash( int initialCapacity, float loadFactor ) { + super(); + initialCapacity = Math.max( 1, initialCapacity ); + _loadFactor = loadFactor; + setUp( HashFunctions.fastCeil( initialCapacity / loadFactor ) ); + } + + + /** + * Returns the capacity of the hash table. This is the true + * physical capacity, without adjusting for the load factor. + * + * @return the physical capacity of the hash table. + */ + public int capacity() { + return _states.length; + } + + + /** + * Delete the record at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _states[index] = REMOVED; + super.removeAt( index ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _states = new byte[capacity]; + return capacity; + } +} // TPrimitiveHash \ No newline at end of file diff --git a/src/gnu/trove/impl/hash/TShortByteHash.java b/src/gnu/trove/impl/hash/TShortByteHash.java new file mode 100644 index 0000000..13f82b9 --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortByteHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short/byte primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortByteHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected byte no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TShortByteHash() { + super(); + no_entry_key = ( short ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortByteHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( short ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TShortByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortByteHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( short ) 0; + no_entry_value = ( byte ) 0; + } + + + /** + * Creates a new TShortByteHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortByteHash( int initialCapacity, float loadFactor, + short no_entry_key, byte no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short key ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( short key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + } +} // TShortByteHash diff --git a/src/gnu/trove/impl/hash/TShortCharHash.java b/src/gnu/trove/impl/hash/TShortCharHash.java new file mode 100644 index 0000000..0d07c5e --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortCharHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short/char primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortCharHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected char no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TShortCharHash() { + super(); + no_entry_key = ( short ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortCharHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( short ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TShortCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortCharHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( short ) 0; + no_entry_value = ( char ) 0; + } + + + /** + * Creates a new TShortCharHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortCharHash( int initialCapacity, float loadFactor, + short no_entry_key, char no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short key ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( short key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + } +} // TShortCharHash diff --git a/src/gnu/trove/impl/hash/TShortDoubleHash.java b/src/gnu/trove/impl/hash/TShortDoubleHash.java new file mode 100644 index 0000000..88da2d3 --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortDoubleHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short/double primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortDoubleHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected double no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TShortDoubleHash() { + super(); + no_entry_key = ( short ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortDoubleHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( short ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TShortDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortDoubleHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( short ) 0; + no_entry_value = ( double ) 0; + } + + + /** + * Creates a new TShortDoubleHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortDoubleHash( int initialCapacity, float loadFactor, + short no_entry_key, double no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short key ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( short key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + } +} // TShortDoubleHash diff --git a/src/gnu/trove/impl/hash/TShortFloatHash.java b/src/gnu/trove/impl/hash/TShortFloatHash.java new file mode 100644 index 0000000..a6b0b8b --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortFloatHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short/float primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortFloatHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected float no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TShortFloatHash() { + super(); + no_entry_key = ( short ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortFloatHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( short ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TShortFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortFloatHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( short ) 0; + no_entry_value = ( float ) 0; + } + + + /** + * Creates a new TShortFloatHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortFloatHash( int initialCapacity, float loadFactor, + short no_entry_key, float no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short key ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( short key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + } +} // TShortFloatHash diff --git a/src/gnu/trove/impl/hash/TShortHash.java b/src/gnu/trove/impl/hash/TShortHash.java new file mode 100644 index 0000000..c146412 --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortHash.java @@ -0,0 +1,334 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.Constants; + +import java.util.Arrays; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short primitives. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + + /** + * Creates a new TShortHash instance with the default + * capacity and load factor. + */ + public TShortHash() { + super(); + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TShortHash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortHash( int initialCapacity, float loadFactor, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_value = no_entry_value; + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_value; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param val an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short val ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( val ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == val) + return index; + + return indexRehashed(val, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param val an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + +} // TShortHash diff --git a/src/gnu/trove/impl/hash/TShortIntHash.java b/src/gnu/trove/impl/hash/TShortIntHash.java new file mode 100644 index 0000000..33dbef4 --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortIntHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short/int primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortIntHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected int no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TShortIntHash() { + super(); + no_entry_key = ( short ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortIntHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( short ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TShortIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortIntHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( short ) 0; + no_entry_value = ( int ) 0; + } + + + /** + * Creates a new TShortIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortIntHash( int initialCapacity, float loadFactor, + short no_entry_key, int no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short key ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( short key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + } +} // TShortIntHash diff --git a/src/gnu/trove/impl/hash/TShortLongHash.java b/src/gnu/trove/impl/hash/TShortLongHash.java new file mode 100644 index 0000000..fc8ab21 --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortLongHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short/long primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortLongHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected long no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TShortLongHash() { + super(); + no_entry_key = ( short ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortLongHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( short ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TShortLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortLongHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( short ) 0; + no_entry_value = ( long ) 0; + } + + + /** + * Creates a new TShortLongHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortLongHash( int initialCapacity, float loadFactor, + short no_entry_key, long no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short key ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( short key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + } +} // TShortLongHash diff --git a/src/gnu/trove/impl/hash/TShortShortHash.java b/src/gnu/trove/impl/hash/TShortShortHash.java new file mode 100644 index 0000000..b0d94a8 --- /dev/null +++ b/src/gnu/trove/impl/hash/TShortShortHash.java @@ -0,0 +1,464 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.hash; + +import gnu.trove.procedure.*; +import gnu.trove.impl.HashFunctions; + +import java.io.ObjectOutput; +import java.io.ObjectInput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed hashing implementation for short/short primitive entries. + * + * Created: Sun Nov 4 08:56:06 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $ + */ +abstract public class TShortShortHash extends TPrimitiveHash { + static final long serialVersionUID = 1L; + + /** the set of shorts */ + public transient short[] _set; + + + /** + * key that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_key; + + + /** + * value that represents null + * + * NOTE: should not be modified after the Hash is created, but is + * not final because of Externalization + * + */ + protected short no_entry_value; + + protected boolean consumeFreeSlot; + + /** + * Creates a new T#E#Hash instance with the default + * capacity and load factor. + */ + public TShortShortHash() { + super(); + no_entry_key = ( short ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new T#E#Hash instance whose capacity + * is the next highest prime above initialCapacity + 1 + * unless that value is already prime. + * + * @param initialCapacity an int value + */ + public TShortShortHash( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = ( short ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TShortShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortShortHash( int initialCapacity, float loadFactor ) { + super(initialCapacity, loadFactor); + no_entry_key = ( short ) 0; + no_entry_value = ( short ) 0; + } + + + /** + * Creates a new TShortShortHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param no_entry_value value that represents null + */ + public TShortShortHash( int initialCapacity, float loadFactor, + short no_entry_key, short no_entry_value ) { + super(initialCapacity, loadFactor); + this.no_entry_key = no_entry_key; + this.no_entry_value = no_entry_value; + } + + + /** + * Returns the value that is used to represent null as a key. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _set = new short[capacity]; + return capacity; + } + + + /** + * Searches the set for val + * + * @param val an short value + * @return a boolean value + */ + public boolean contains( short val ) { + return index(val) >= 0; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + public boolean forEach( TShortProcedure procedure ) { + byte[] states = _states; + short[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( set[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Releases the element currently stored at index. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _set[index] = no_entry_key; + super.removeAt( index ); + } + + + /** + * Locates the index of val. + * + * @param key an short value + * @return the index of val or -1 if it isn't in the set. + */ + protected int index( short key ) { + int hash, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + if (state == FREE) + return -1; + + if (state == FULL && set[index] == key) + return index; + + return indexRehashed(key, index, hash, state); + } + + int indexRehashed(short key, int index, int hash, byte state) { + // see Knuth, p. 529 + int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + + do { + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + // + if (state == FREE) + return -1; + + // + if (key == _set[index] && state != REMOVED) + return index; + } while (index != loopIndex); + + return -1; + } + + + /** + * Locates the index at which val can be inserted. if + * there is already a value equal()ing val in the set, + * returns that value as a negative integer. + * + * @param key an short value + * @return an int value + */ + protected int insertKey( short val ) { + int hash, index; + + hash = HashFunctions.hash(val) & 0x7fffffff; + index = hash % _states.length; + byte state = _states[index]; + + consumeFreeSlot = false; + + if (state == FREE) { + consumeFreeSlot = true; + insertKeyAt(index, val); + + return index; // empty, all done + } + + if (state == FULL && _set[index] == val) { + return -index - 1; // already stored + } + + // already FULL or REMOVED, must probe + return insertKeyRehash(val, index, hash, state); + } + + int insertKeyRehash(short val, int index, int hash, byte state) { + // compute the double hash + final int length = _set.length; + int probe = 1 + (hash % (length - 2)); + final int loopIndex = index; + int firstRemoved = -1; + + /** + * Look until FREE slot or we start to loop + */ + do { + // Identify first removed slot + if (state == REMOVED && firstRemoved == -1) + firstRemoved = index; + + index -= probe; + if (index < 0) { + index += length; + } + state = _states[index]; + + // A FREE slot stops the search + if (state == FREE) { + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } else { + consumeFreeSlot = true; + insertKeyAt(index, val); + return index; + } + } + + if (state == FULL && _set[index] == val) { + return -index - 1; + } + + // Detect loop + } while (index != loopIndex); + + // We inspected all reachable slots and did not find a FREE one + // If we found a REMOVED slot we return the first one found + if (firstRemoved != -1) { + insertKeyAt(firstRemoved, val); + return firstRemoved; + } + + // Can a resizing strategy be found that resizes the set? + throw new IllegalStateException("No free or removed slots available. Key set full?!!"); + } + + void insertKeyAt(int index, short val) { + _set[index] = val; // insert value + _states[index] = FULL; + } + + protected int XinsertKey( short key ) { + int hash, probe, index, length; + + final byte[] states = _states; + final short[] set = _set; + length = states.length; + hash = HashFunctions.hash( key ) & 0x7fffffff; + index = hash % length; + byte state = states[index]; + + consumeFreeSlot = false; + + if ( state == FREE ) { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; // empty, all done + } else if ( state == FULL && set[index] == key ) { + return -index -1; // already stored + } else { // already FULL or REMOVED, must probe + // compute the double hash + probe = 1 + ( hash % ( length - 2 ) ); + + // if the slot we landed on is FULL (but not removed), probe + // until we find an empty slot, a REMOVED slot, or an element + // equal to the one we are trying to insert. + // finding an empty slot means that the value is not present + // and that we should use that slot as the insertion point; + // finding a REMOVED slot means that we need to keep searching, + // however we want to remember the offset of that REMOVED slot + // so we can reuse it in case a "new" insertion (i.e. not an update) + // is possible. + // finding a matching value means that we've found that our desired + // key is already in the table + + if ( state != REMOVED ) { + // starting at the natural offset, probe until we find an + // offset that isn't full. + do { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } while ( state == FULL && set[index] != key ); + } + + // if the index we found was removed: continue probing until we + // locate a free location or an element which equal()s the + // one we have. + if ( state == REMOVED) { + int firstRemoved = index; + while ( state != FREE && ( state == REMOVED || set[index] != key ) ) { + index -= probe; + if (index < 0) { + index += length; + } + state = states[index]; + } + + if (state == FULL) { + return -index -1; + } else { + set[index] = key; + states[index] = FULL; + + return firstRemoved; + } + } + // if it's full, the key is already stored + if (state == FULL) { + return -index -1; + } else { + consumeFreeSlot = true; + set[index] = key; + states[index] = FULL; + + return index; + } + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + } +} // TShortShortHash diff --git a/src/gnu/trove/impl/package.html b/src/gnu/trove/impl/package.html new file mode 100644 index 0000000..c803363 --- /dev/null +++ b/src/gnu/trove/impl/package.html @@ -0,0 +1,24 @@ + + +This package (and its sub-packages) contain internal implementations used in Trove. These +classes should not be accessed directly (treat them like com.sun +classes. + \ No newline at end of file diff --git a/src/gnu/trove/impl/sync/SynchronizedCollection.java b/src/gnu/trove/impl/sync/SynchronizedCollection.java new file mode 100644 index 0000000..b677743 --- /dev/null +++ b/src/gnu/trove/impl/sync/SynchronizedCollection.java @@ -0,0 +1,91 @@ +// //////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// //////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; + + +/** + * + */ +class SynchronizedCollection implements Collection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final Collection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + SynchronizedCollection( Collection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( Object o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public Object[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + @SuppressWarnings({}) + public T[] toArray( T[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public Iterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( E e ) { + synchronized( mutex ) { return c.add( e ); } + } + public boolean remove( Object o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll ); } + } + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} \ No newline at end of file diff --git a/src/gnu/trove/impl/sync/SynchronizedSet.java b/src/gnu/trove/impl/sync/SynchronizedSet.java new file mode 100644 index 0000000..0e4062e --- /dev/null +++ b/src/gnu/trove/impl/sync/SynchronizedSet.java @@ -0,0 +1,31 @@ +// //////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// //////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + +import java.util.Set; + + +/** Local implementation of SynchronizedSet so we can set the mutex explicitly. */ +class SynchronizedSet extends SynchronizedCollection implements Set { + private static final long serialVersionUID = 487447009682186044L; + + SynchronizedSet( Set s, Object mutex ) { super( s, mutex ); } + public boolean equals( Object o ) { synchronized( mutex ) { return c.equals( o ); } } + public int hashCode() { synchronized( mutex ) { return c.hashCode(); } } +} \ No newline at end of file diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteByteMap.java new file mode 100644 index 0000000..8f5d35c --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteByteMap implements TByteByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteByteMap( TByteByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteByteMap( TByteByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( byte key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient TByteCollection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( byte key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( byte key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( byte key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( byte key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteCharMap.java new file mode 100644 index 0000000..3559a6d --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteCharMap implements TByteCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteCharMap( TByteCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteCharMap( TByteCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( byte key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient TCharCollection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( byte key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( byte key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( byte key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( byte key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteCollection.java b/src/gnu/trove/impl/sync/TSynchronizedByteCollection.java new file mode 100644 index 0000000..fc43495 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteCollection.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteCollection implements TByteCollection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final TByteCollection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteCollection( TByteCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + mutex = this; + } + public TSynchronizedByteCollection( TByteCollection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( byte o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public byte[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + public byte[] toArray( byte[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public TByteIterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( byte e ) { + synchronized (mutex ) { return c.add( e ); } + } + public boolean remove( byte o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( TByteCollection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( byte[] array ) { + synchronized( mutex ) { return c.containsAll( array );} + } + + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( TByteCollection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( byte[] array ) { + synchronized( mutex ) { return c.addAll( array ); } + } + + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( TByteCollection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( byte[] array ) { + synchronized( mutex ) { return c.removeAll( array ); } + } + + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( TByteCollection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( byte[] array ) { + synchronized( mutex ) { return c.retainAll( array ); } + } + + public byte getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TByteProcedure procedure ) { + synchronized( mutex ) { return c.forEach( procedure ); } + } + + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteDoubleMap.java new file mode 100644 index 0000000..c3fa309 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteDoubleMap implements TByteDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteDoubleMap( TByteDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteDoubleMap( TByteDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( byte key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient TDoubleCollection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( byte key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( byte key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( byte key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( byte key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteFloatMap.java new file mode 100644 index 0000000..6bf2b48 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteFloatMap implements TByteFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteFloatMap( TByteFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteFloatMap( TByteFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( byte key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient TFloatCollection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( byte key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( byte key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( byte key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( byte key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteIntMap.java new file mode 100644 index 0000000..8d39d5e --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteIntMap implements TByteIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteIntMap( TByteIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteIntMap( TByteIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( byte key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient TIntCollection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( byte key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( byte key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( byte key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( byte key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteList.java b/src/gnu/trove/impl/sync/TSynchronizedByteList.java new file mode 100644 index 0000000..5e6302f --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteList.java @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TSynchronizedByteList extends TSynchronizedByteCollection + implements TByteList { + + static final long serialVersionUID = -7754090372962971524L; + + final TByteList list; + + public TSynchronizedByteList( TByteList list ) { + super( list ); + this.list = list; + } + public TSynchronizedByteList( TByteList list, Object mutex ) { + super( list, mutex ); + this.list = list; + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return list.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return list.hashCode(); } + } + + public byte get( int index ) { + synchronized( mutex ) { return list.get( index ); } + } + public byte set( int index, byte element) { + synchronized( mutex ) { return list.set( index, element ); } + } + public void set( int offset, byte[] values ) { + synchronized( mutex ) { list.set( offset, values ); } + } + public void set( int offset, byte[] values, int valOffset, int length ) { + synchronized( mutex ) { list.set( offset, values, valOffset, length ); } + } + + public byte replace( int offset, byte val ) { + synchronized( mutex ) { return list.replace( offset, val ); } + } + public void remove( int offset, int length ) { + synchronized( mutex ) { list.remove( offset, length ); } + } + public byte removeAt( int offset ) { + synchronized( mutex ) { return list.removeAt( offset ); } + } + + public void add( byte[] vals ) { + synchronized( mutex ) { list.add( vals ); } + } + public void add( byte[] vals, int offset, int length ) { + synchronized( mutex ) { list.add( vals, offset, length ); } + } + + public void insert( int offset, byte value ) { + synchronized( mutex ) { list.insert( offset, value ); } + } + public void insert( int offset, byte[] values ) { + synchronized( mutex ) { list.insert( offset, values ); } + } + public void insert( int offset, byte[] values, int valOffset, int len ) { + synchronized( mutex ) { list.insert( offset, values, valOffset, len ); } + } + + public int indexOf( byte o ) { + synchronized( mutex ) { return list.indexOf( o ); } + } + public int lastIndexOf( byte o ) { + synchronized( mutex ) { return list.lastIndexOf( o ); } + } + +// public TListByteIterator listIterator() { +// return list.listIterator(); // Must be manually synched by user +// } + +// public TListByteIterator listIterator( int index ) { +// return list.listIterator( index ); // Must be manually synched by user +// } + + public TByteList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedByteList( list.subList( fromIndex, toIndex ), + mutex ); + } + } + + public byte[] toArray( int offset, int len ) { + synchronized( mutex ) { return list.toArray( offset, len ); } + } + public byte[] toArray( byte[] dest, int offset, int len ) { + synchronized( mutex ) { return list.toArray( dest, offset, len ); } + } + public byte[] toArray( byte[] dest, int source_pos, int dest_pos, int len ) { + synchronized( mutex ) { return list.toArray( dest, source_pos, dest_pos, len ); } + } + + public int indexOf( int offset, byte value ) { + synchronized( mutex ) { return list.indexOf( offset, value ); } + } + public int lastIndexOf( int offset, byte value ) { + synchronized( mutex ) { return list.lastIndexOf( offset, value ); } + } + + public void fill( byte val ) { + synchronized( mutex ) { list.fill( val ); } + } + public void fill( int fromIndex, int toIndex, byte val ) { + synchronized( mutex ) { list.fill( fromIndex, toIndex, val ); } + } + + public void reverse() { + synchronized( mutex ) { list.reverse(); } + } + public void reverse( int from, int to ) { + synchronized( mutex ) { list.reverse( from, to ); } + } + + public void shuffle( Random rand ) { + synchronized( mutex ) { list.shuffle( rand ); } + } + + public void sort() { + synchronized( mutex ) { list.sort(); } + } + public void sort( int fromIndex, int toIndex ) { + synchronized( mutex ) { list.sort( fromIndex, toIndex ); } + } + + public int binarySearch( byte value ) { + synchronized( mutex ) { return list.binarySearch( value ); } + } + public int binarySearch( byte value, int fromIndex, int toIndex ) { + synchronized( mutex ) { return list.binarySearch( value, fromIndex, toIndex ); } + } + + public TByteList grep( TByteProcedure condition ) { + synchronized( mutex ) { return list.grep( condition ); } + } + public TByteList inverseGrep( TByteProcedure condition ) { + synchronized( mutex ) { return list.inverseGrep( condition ); } + } + + public byte max() { synchronized( mutex ) { return list.max(); } } + public byte min() { synchronized( mutex ) { return list.min(); } } + public byte sum() { synchronized( mutex ) { return list.sum(); } } + + public boolean forEachDescending( TByteProcedure procedure ) { + synchronized( mutex ) { return list.forEachDescending( procedure ); } + } + + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { list.transformValues( function ); } + } + + /** + * SynchronizedRandomAccessList instances are serialized as + * SynchronizedList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * SynchronizedList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, SynchronizedRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * SynchronizedList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TSynchronizedRandomAccessByteList( list ) + : this ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteLongMap.java new file mode 100644 index 0000000..98ec189 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteLongMap implements TByteLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteLongMap( TByteLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteLongMap( TByteLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( byte key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient TLongCollection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( byte key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( byte key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( byte key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( byte key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteObjectMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteObjectMap.java new file mode 100644 index 0000000..ac39882 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteObjectMap.java @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import java.util.Collection; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteObjectMap + implements TByteObjectMap, Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteObjectMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteObjectMap( TByteObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteObjectMap( TByteObjectMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( Object value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public V get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public V put( byte key, V value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public V remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteObjectMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient Collection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public Collection valueCollection() { + synchronized( mutex ) { + if ( values == null ) { + values = new SynchronizedCollection( m.valueCollection(), mutex ); + } + return values; + } + } + public Object[] values() { + synchronized( mutex ) { return m.values(); } + } + public V[] values( V[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteObjectIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + + public V putIfAbsent( byte key, V value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TObjectFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteObjectProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteSet.java b/src/gnu/trove/impl/sync/TSynchronizedByteSet.java new file mode 100644 index 0000000..628c4b7 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteSet.java @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; + + +public class TSynchronizedByteSet extends TSynchronizedByteCollection + implements TByteSet { + + private static final long serialVersionUID = 487447009682186044L; + + public TSynchronizedByteSet( TByteSet s ) { + super( s ); + } + public TSynchronizedByteSet( TByteSet s, Object mutex ) { + super( s, mutex ); + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return c.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return c.hashCode(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedByteShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedByteShortMap.java new file mode 100644 index 0000000..4d23906 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedByteShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedByteShortMap implements TByteShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TByteShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedByteShortMap( TByteShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedByteShortMap( TByteShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( byte key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( byte key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( byte key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( byte key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TByteShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TByteSet keySet = null; + private transient TShortCollection values = null; + + public TByteSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedByteSet( m.keySet(), mutex ); + return keySet; + } + } + public byte[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public byte[] keys( byte[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TByteShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( byte key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TByteShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TByteShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( byte key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( byte key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( byte key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharByteMap.java new file mode 100644 index 0000000..3aedbf3 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharByteMap implements TCharByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharByteMap( TCharByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharByteMap( TCharByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( char key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient TByteCollection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( char key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( char key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( char key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( char key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharCharMap.java new file mode 100644 index 0000000..8c0faac --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharCharMap implements TCharCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharCharMap( TCharCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharCharMap( TCharCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( char key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient TCharCollection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( char key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( char key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( char key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( char key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharCollection.java b/src/gnu/trove/impl/sync/TSynchronizedCharCollection.java new file mode 100644 index 0000000..ce8c9e3 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharCollection.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharCollection implements TCharCollection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final TCharCollection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharCollection( TCharCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + mutex = this; + } + public TSynchronizedCharCollection( TCharCollection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( char o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public char[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + public char[] toArray( char[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public TCharIterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( char e ) { + synchronized (mutex ) { return c.add( e ); } + } + public boolean remove( char o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( TCharCollection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( char[] array ) { + synchronized( mutex ) { return c.containsAll( array );} + } + + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( TCharCollection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( char[] array ) { + synchronized( mutex ) { return c.addAll( array ); } + } + + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( TCharCollection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( char[] array ) { + synchronized( mutex ) { return c.removeAll( array ); } + } + + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( TCharCollection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( char[] array ) { + synchronized( mutex ) { return c.retainAll( array ); } + } + + public char getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TCharProcedure procedure ) { + synchronized( mutex ) { return c.forEach( procedure ); } + } + + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharDoubleMap.java new file mode 100644 index 0000000..bc48097 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharDoubleMap implements TCharDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharDoubleMap( TCharDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharDoubleMap( TCharDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( char key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient TDoubleCollection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( char key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( char key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( char key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( char key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharFloatMap.java new file mode 100644 index 0000000..c1c703d --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharFloatMap implements TCharFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharFloatMap( TCharFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharFloatMap( TCharFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( char key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient TFloatCollection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( char key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( char key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( char key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( char key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharIntMap.java new file mode 100644 index 0000000..d454f0b --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharIntMap implements TCharIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharIntMap( TCharIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharIntMap( TCharIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( char key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient TIntCollection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( char key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( char key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( char key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( char key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharList.java b/src/gnu/trove/impl/sync/TSynchronizedCharList.java new file mode 100644 index 0000000..a4510c1 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharList.java @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TSynchronizedCharList extends TSynchronizedCharCollection + implements TCharList { + + static final long serialVersionUID = -7754090372962971524L; + + final TCharList list; + + public TSynchronizedCharList( TCharList list ) { + super( list ); + this.list = list; + } + public TSynchronizedCharList( TCharList list, Object mutex ) { + super( list, mutex ); + this.list = list; + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return list.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return list.hashCode(); } + } + + public char get( int index ) { + synchronized( mutex ) { return list.get( index ); } + } + public char set( int index, char element) { + synchronized( mutex ) { return list.set( index, element ); } + } + public void set( int offset, char[] values ) { + synchronized( mutex ) { list.set( offset, values ); } + } + public void set( int offset, char[] values, int valOffset, int length ) { + synchronized( mutex ) { list.set( offset, values, valOffset, length ); } + } + + public char replace( int offset, char val ) { + synchronized( mutex ) { return list.replace( offset, val ); } + } + public void remove( int offset, int length ) { + synchronized( mutex ) { list.remove( offset, length ); } + } + public char removeAt( int offset ) { + synchronized( mutex ) { return list.removeAt( offset ); } + } + + public void add( char[] vals ) { + synchronized( mutex ) { list.add( vals ); } + } + public void add( char[] vals, int offset, int length ) { + synchronized( mutex ) { list.add( vals, offset, length ); } + } + + public void insert( int offset, char value ) { + synchronized( mutex ) { list.insert( offset, value ); } + } + public void insert( int offset, char[] values ) { + synchronized( mutex ) { list.insert( offset, values ); } + } + public void insert( int offset, char[] values, int valOffset, int len ) { + synchronized( mutex ) { list.insert( offset, values, valOffset, len ); } + } + + public int indexOf( char o ) { + synchronized( mutex ) { return list.indexOf( o ); } + } + public int lastIndexOf( char o ) { + synchronized( mutex ) { return list.lastIndexOf( o ); } + } + +// public TListCharIterator listIterator() { +// return list.listIterator(); // Must be manually synched by user +// } + +// public TListCharIterator listIterator( int index ) { +// return list.listIterator( index ); // Must be manually synched by user +// } + + public TCharList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedCharList( list.subList( fromIndex, toIndex ), + mutex ); + } + } + + public char[] toArray( int offset, int len ) { + synchronized( mutex ) { return list.toArray( offset, len ); } + } + public char[] toArray( char[] dest, int offset, int len ) { + synchronized( mutex ) { return list.toArray( dest, offset, len ); } + } + public char[] toArray( char[] dest, int source_pos, int dest_pos, int len ) { + synchronized( mutex ) { return list.toArray( dest, source_pos, dest_pos, len ); } + } + + public int indexOf( int offset, char value ) { + synchronized( mutex ) { return list.indexOf( offset, value ); } + } + public int lastIndexOf( int offset, char value ) { + synchronized( mutex ) { return list.lastIndexOf( offset, value ); } + } + + public void fill( char val ) { + synchronized( mutex ) { list.fill( val ); } + } + public void fill( int fromIndex, int toIndex, char val ) { + synchronized( mutex ) { list.fill( fromIndex, toIndex, val ); } + } + + public void reverse() { + synchronized( mutex ) { list.reverse(); } + } + public void reverse( int from, int to ) { + synchronized( mutex ) { list.reverse( from, to ); } + } + + public void shuffle( Random rand ) { + synchronized( mutex ) { list.shuffle( rand ); } + } + + public void sort() { + synchronized( mutex ) { list.sort(); } + } + public void sort( int fromIndex, int toIndex ) { + synchronized( mutex ) { list.sort( fromIndex, toIndex ); } + } + + public int binarySearch( char value ) { + synchronized( mutex ) { return list.binarySearch( value ); } + } + public int binarySearch( char value, int fromIndex, int toIndex ) { + synchronized( mutex ) { return list.binarySearch( value, fromIndex, toIndex ); } + } + + public TCharList grep( TCharProcedure condition ) { + synchronized( mutex ) { return list.grep( condition ); } + } + public TCharList inverseGrep( TCharProcedure condition ) { + synchronized( mutex ) { return list.inverseGrep( condition ); } + } + + public char max() { synchronized( mutex ) { return list.max(); } } + public char min() { synchronized( mutex ) { return list.min(); } } + public char sum() { synchronized( mutex ) { return list.sum(); } } + + public boolean forEachDescending( TCharProcedure procedure ) { + synchronized( mutex ) { return list.forEachDescending( procedure ); } + } + + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { list.transformValues( function ); } + } + + /** + * SynchronizedRandomAccessList instances are serialized as + * SynchronizedList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * SynchronizedList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, SynchronizedRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * SynchronizedList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TSynchronizedRandomAccessCharList( list ) + : this ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharLongMap.java new file mode 100644 index 0000000..9479340 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharLongMap implements TCharLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharLongMap( TCharLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharLongMap( TCharLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( char key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient TLongCollection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( char key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( char key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( char key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( char key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharObjectMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharObjectMap.java new file mode 100644 index 0000000..d4e7d70 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharObjectMap.java @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import java.util.Collection; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharObjectMap + implements TCharObjectMap, Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharObjectMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharObjectMap( TCharObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharObjectMap( TCharObjectMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( Object value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public V get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public V put( char key, V value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public V remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharObjectMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient Collection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public Collection valueCollection() { + synchronized( mutex ) { + if ( values == null ) { + values = new SynchronizedCollection( m.valueCollection(), mutex ); + } + return values; + } + } + public Object[] values() { + synchronized( mutex ) { return m.values(); } + } + public V[] values( V[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharObjectIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + + public V putIfAbsent( char key, V value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TObjectFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharObjectProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharSet.java b/src/gnu/trove/impl/sync/TSynchronizedCharSet.java new file mode 100644 index 0000000..2a55881 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharSet.java @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; + + +public class TSynchronizedCharSet extends TSynchronizedCharCollection + implements TCharSet { + + private static final long serialVersionUID = 487447009682186044L; + + public TSynchronizedCharSet( TCharSet s ) { + super( s ); + } + public TSynchronizedCharSet( TCharSet s, Object mutex ) { + super( s, mutex ); + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return c.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return c.hashCode(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedCharShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedCharShortMap.java new file mode 100644 index 0000000..f2db427 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedCharShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedCharShortMap implements TCharShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TCharShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedCharShortMap( TCharShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedCharShortMap( TCharShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( char key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( char key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( char key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( char key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TCharShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TCharSet keySet = null; + private transient TShortCollection values = null; + + public TCharSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedCharSet( m.keySet(), mutex ); + return keySet; + } + } + public char[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public char[] keys( char[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TCharShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public char getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( char key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TCharShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TCharShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( char key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( char key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( char key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleByteMap.java new file mode 100644 index 0000000..aa43411 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleByteMap implements TDoubleByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleByteMap( TDoubleByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleByteMap( TDoubleByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( double key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient TByteCollection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( double key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( double key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( double key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( double key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleCharMap.java new file mode 100644 index 0000000..a0a45d3 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleCharMap implements TDoubleCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleCharMap( TDoubleCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleCharMap( TDoubleCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( double key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient TCharCollection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( double key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( double key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( double key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( double key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleCollection.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleCollection.java new file mode 100644 index 0000000..6bd7aa4 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleCollection.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleCollection implements TDoubleCollection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final TDoubleCollection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleCollection( TDoubleCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + mutex = this; + } + public TSynchronizedDoubleCollection( TDoubleCollection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( double o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public double[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + public double[] toArray( double[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public TDoubleIterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( double e ) { + synchronized (mutex ) { return c.add( e ); } + } + public boolean remove( double o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( TDoubleCollection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( double[] array ) { + synchronized( mutex ) { return c.containsAll( array );} + } + + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( TDoubleCollection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( double[] array ) { + synchronized( mutex ) { return c.addAll( array ); } + } + + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( TDoubleCollection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( double[] array ) { + synchronized( mutex ) { return c.removeAll( array ); } + } + + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( TDoubleCollection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( double[] array ) { + synchronized( mutex ) { return c.retainAll( array ); } + } + + public double getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TDoubleProcedure procedure ) { + synchronized( mutex ) { return c.forEach( procedure ); } + } + + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleDoubleMap.java new file mode 100644 index 0000000..484e45c --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleDoubleMap implements TDoubleDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleDoubleMap( TDoubleDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleDoubleMap( TDoubleDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( double key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient TDoubleCollection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( double key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( double key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( double key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( double key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleFloatMap.java new file mode 100644 index 0000000..354d41e --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleFloatMap implements TDoubleFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleFloatMap( TDoubleFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleFloatMap( TDoubleFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( double key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient TFloatCollection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( double key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( double key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( double key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( double key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleIntMap.java new file mode 100644 index 0000000..fd815f9 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleIntMap implements TDoubleIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleIntMap( TDoubleIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleIntMap( TDoubleIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( double key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient TIntCollection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( double key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( double key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( double key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( double key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleList.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleList.java new file mode 100644 index 0000000..77fcb38 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleList.java @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TSynchronizedDoubleList extends TSynchronizedDoubleCollection + implements TDoubleList { + + static final long serialVersionUID = -7754090372962971524L; + + final TDoubleList list; + + public TSynchronizedDoubleList( TDoubleList list ) { + super( list ); + this.list = list; + } + public TSynchronizedDoubleList( TDoubleList list, Object mutex ) { + super( list, mutex ); + this.list = list; + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return list.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return list.hashCode(); } + } + + public double get( int index ) { + synchronized( mutex ) { return list.get( index ); } + } + public double set( int index, double element) { + synchronized( mutex ) { return list.set( index, element ); } + } + public void set( int offset, double[] values ) { + synchronized( mutex ) { list.set( offset, values ); } + } + public void set( int offset, double[] values, int valOffset, int length ) { + synchronized( mutex ) { list.set( offset, values, valOffset, length ); } + } + + public double replace( int offset, double val ) { + synchronized( mutex ) { return list.replace( offset, val ); } + } + public void remove( int offset, int length ) { + synchronized( mutex ) { list.remove( offset, length ); } + } + public double removeAt( int offset ) { + synchronized( mutex ) { return list.removeAt( offset ); } + } + + public void add( double[] vals ) { + synchronized( mutex ) { list.add( vals ); } + } + public void add( double[] vals, int offset, int length ) { + synchronized( mutex ) { list.add( vals, offset, length ); } + } + + public void insert( int offset, double value ) { + synchronized( mutex ) { list.insert( offset, value ); } + } + public void insert( int offset, double[] values ) { + synchronized( mutex ) { list.insert( offset, values ); } + } + public void insert( int offset, double[] values, int valOffset, int len ) { + synchronized( mutex ) { list.insert( offset, values, valOffset, len ); } + } + + public int indexOf( double o ) { + synchronized( mutex ) { return list.indexOf( o ); } + } + public int lastIndexOf( double o ) { + synchronized( mutex ) { return list.lastIndexOf( o ); } + } + +// public TListDoubleIterator listIterator() { +// return list.listIterator(); // Must be manually synched by user +// } + +// public TListDoubleIterator listIterator( int index ) { +// return list.listIterator( index ); // Must be manually synched by user +// } + + public TDoubleList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedDoubleList( list.subList( fromIndex, toIndex ), + mutex ); + } + } + + public double[] toArray( int offset, int len ) { + synchronized( mutex ) { return list.toArray( offset, len ); } + } + public double[] toArray( double[] dest, int offset, int len ) { + synchronized( mutex ) { return list.toArray( dest, offset, len ); } + } + public double[] toArray( double[] dest, int source_pos, int dest_pos, int len ) { + synchronized( mutex ) { return list.toArray( dest, source_pos, dest_pos, len ); } + } + + public int indexOf( int offset, double value ) { + synchronized( mutex ) { return list.indexOf( offset, value ); } + } + public int lastIndexOf( int offset, double value ) { + synchronized( mutex ) { return list.lastIndexOf( offset, value ); } + } + + public void fill( double val ) { + synchronized( mutex ) { list.fill( val ); } + } + public void fill( int fromIndex, int toIndex, double val ) { + synchronized( mutex ) { list.fill( fromIndex, toIndex, val ); } + } + + public void reverse() { + synchronized( mutex ) { list.reverse(); } + } + public void reverse( int from, int to ) { + synchronized( mutex ) { list.reverse( from, to ); } + } + + public void shuffle( Random rand ) { + synchronized( mutex ) { list.shuffle( rand ); } + } + + public void sort() { + synchronized( mutex ) { list.sort(); } + } + public void sort( int fromIndex, int toIndex ) { + synchronized( mutex ) { list.sort( fromIndex, toIndex ); } + } + + public int binarySearch( double value ) { + synchronized( mutex ) { return list.binarySearch( value ); } + } + public int binarySearch( double value, int fromIndex, int toIndex ) { + synchronized( mutex ) { return list.binarySearch( value, fromIndex, toIndex ); } + } + + public TDoubleList grep( TDoubleProcedure condition ) { + synchronized( mutex ) { return list.grep( condition ); } + } + public TDoubleList inverseGrep( TDoubleProcedure condition ) { + synchronized( mutex ) { return list.inverseGrep( condition ); } + } + + public double max() { synchronized( mutex ) { return list.max(); } } + public double min() { synchronized( mutex ) { return list.min(); } } + public double sum() { synchronized( mutex ) { return list.sum(); } } + + public boolean forEachDescending( TDoubleProcedure procedure ) { + synchronized( mutex ) { return list.forEachDescending( procedure ); } + } + + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { list.transformValues( function ); } + } + + /** + * SynchronizedRandomAccessList instances are serialized as + * SynchronizedList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * SynchronizedList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, SynchronizedRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * SynchronizedList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TSynchronizedRandomAccessDoubleList( list ) + : this ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleLongMap.java new file mode 100644 index 0000000..f444106 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleLongMap implements TDoubleLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleLongMap( TDoubleLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleLongMap( TDoubleLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( double key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient TLongCollection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( double key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( double key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( double key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( double key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleObjectMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleObjectMap.java new file mode 100644 index 0000000..152f1a1 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleObjectMap.java @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import java.util.Collection; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleObjectMap + implements TDoubleObjectMap, Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleObjectMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleObjectMap( TDoubleObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleObjectMap( TDoubleObjectMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( Object value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public V get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public V put( double key, V value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public V remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleObjectMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient Collection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public Collection valueCollection() { + synchronized( mutex ) { + if ( values == null ) { + values = new SynchronizedCollection( m.valueCollection(), mutex ); + } + return values; + } + } + public Object[] values() { + synchronized( mutex ) { return m.values(); } + } + public V[] values( V[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleObjectIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + + public V putIfAbsent( double key, V value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TObjectFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleObjectProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleSet.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleSet.java new file mode 100644 index 0000000..1b4f1db --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleSet.java @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; + + +public class TSynchronizedDoubleSet extends TSynchronizedDoubleCollection + implements TDoubleSet { + + private static final long serialVersionUID = 487447009682186044L; + + public TSynchronizedDoubleSet( TDoubleSet s ) { + super( s ); + } + public TSynchronizedDoubleSet( TDoubleSet s, Object mutex ) { + super( s, mutex ); + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return c.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return c.hashCode(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedDoubleShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedDoubleShortMap.java new file mode 100644 index 0000000..2142104 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedDoubleShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedDoubleShortMap implements TDoubleShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TDoubleShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedDoubleShortMap( TDoubleShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedDoubleShortMap( TDoubleShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( double key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( double key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( double key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( double key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TDoubleShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TDoubleSet keySet = null; + private transient TShortCollection values = null; + + public TDoubleSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedDoubleSet( m.keySet(), mutex ); + return keySet; + } + } + public double[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public double[] keys( double[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TDoubleShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public double getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( double key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TDoubleShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TDoubleShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( double key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( double key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( double key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatByteMap.java new file mode 100644 index 0000000..e3c4fcc --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatByteMap implements TFloatByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatByteMap( TFloatByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatByteMap( TFloatByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( float key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient TByteCollection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( float key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( float key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( float key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( float key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatCharMap.java new file mode 100644 index 0000000..2c05d45 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatCharMap implements TFloatCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatCharMap( TFloatCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatCharMap( TFloatCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( float key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient TCharCollection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( float key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( float key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( float key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( float key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatCollection.java b/src/gnu/trove/impl/sync/TSynchronizedFloatCollection.java new file mode 100644 index 0000000..334f358 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatCollection.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatCollection implements TFloatCollection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final TFloatCollection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatCollection( TFloatCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + mutex = this; + } + public TSynchronizedFloatCollection( TFloatCollection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( float o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public float[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + public float[] toArray( float[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public TFloatIterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( float e ) { + synchronized (mutex ) { return c.add( e ); } + } + public boolean remove( float o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( TFloatCollection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( float[] array ) { + synchronized( mutex ) { return c.containsAll( array );} + } + + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( TFloatCollection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( float[] array ) { + synchronized( mutex ) { return c.addAll( array ); } + } + + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( TFloatCollection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( float[] array ) { + synchronized( mutex ) { return c.removeAll( array ); } + } + + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( TFloatCollection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( float[] array ) { + synchronized( mutex ) { return c.retainAll( array ); } + } + + public float getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TFloatProcedure procedure ) { + synchronized( mutex ) { return c.forEach( procedure ); } + } + + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatDoubleMap.java new file mode 100644 index 0000000..122fb4e --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatDoubleMap implements TFloatDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatDoubleMap( TFloatDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatDoubleMap( TFloatDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( float key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient TDoubleCollection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( float key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( float key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( float key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( float key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatFloatMap.java new file mode 100644 index 0000000..b36c67d --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatFloatMap implements TFloatFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatFloatMap( TFloatFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatFloatMap( TFloatFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( float key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient TFloatCollection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( float key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( float key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( float key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( float key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatIntMap.java new file mode 100644 index 0000000..553b681 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatIntMap implements TFloatIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatIntMap( TFloatIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatIntMap( TFloatIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( float key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient TIntCollection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( float key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( float key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( float key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( float key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatList.java b/src/gnu/trove/impl/sync/TSynchronizedFloatList.java new file mode 100644 index 0000000..51ac43e --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatList.java @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TSynchronizedFloatList extends TSynchronizedFloatCollection + implements TFloatList { + + static final long serialVersionUID = -7754090372962971524L; + + final TFloatList list; + + public TSynchronizedFloatList( TFloatList list ) { + super( list ); + this.list = list; + } + public TSynchronizedFloatList( TFloatList list, Object mutex ) { + super( list, mutex ); + this.list = list; + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return list.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return list.hashCode(); } + } + + public float get( int index ) { + synchronized( mutex ) { return list.get( index ); } + } + public float set( int index, float element) { + synchronized( mutex ) { return list.set( index, element ); } + } + public void set( int offset, float[] values ) { + synchronized( mutex ) { list.set( offset, values ); } + } + public void set( int offset, float[] values, int valOffset, int length ) { + synchronized( mutex ) { list.set( offset, values, valOffset, length ); } + } + + public float replace( int offset, float val ) { + synchronized( mutex ) { return list.replace( offset, val ); } + } + public void remove( int offset, int length ) { + synchronized( mutex ) { list.remove( offset, length ); } + } + public float removeAt( int offset ) { + synchronized( mutex ) { return list.removeAt( offset ); } + } + + public void add( float[] vals ) { + synchronized( mutex ) { list.add( vals ); } + } + public void add( float[] vals, int offset, int length ) { + synchronized( mutex ) { list.add( vals, offset, length ); } + } + + public void insert( int offset, float value ) { + synchronized( mutex ) { list.insert( offset, value ); } + } + public void insert( int offset, float[] values ) { + synchronized( mutex ) { list.insert( offset, values ); } + } + public void insert( int offset, float[] values, int valOffset, int len ) { + synchronized( mutex ) { list.insert( offset, values, valOffset, len ); } + } + + public int indexOf( float o ) { + synchronized( mutex ) { return list.indexOf( o ); } + } + public int lastIndexOf( float o ) { + synchronized( mutex ) { return list.lastIndexOf( o ); } + } + +// public TListFloatIterator listIterator() { +// return list.listIterator(); // Must be manually synched by user +// } + +// public TListFloatIterator listIterator( int index ) { +// return list.listIterator( index ); // Must be manually synched by user +// } + + public TFloatList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedFloatList( list.subList( fromIndex, toIndex ), + mutex ); + } + } + + public float[] toArray( int offset, int len ) { + synchronized( mutex ) { return list.toArray( offset, len ); } + } + public float[] toArray( float[] dest, int offset, int len ) { + synchronized( mutex ) { return list.toArray( dest, offset, len ); } + } + public float[] toArray( float[] dest, int source_pos, int dest_pos, int len ) { + synchronized( mutex ) { return list.toArray( dest, source_pos, dest_pos, len ); } + } + + public int indexOf( int offset, float value ) { + synchronized( mutex ) { return list.indexOf( offset, value ); } + } + public int lastIndexOf( int offset, float value ) { + synchronized( mutex ) { return list.lastIndexOf( offset, value ); } + } + + public void fill( float val ) { + synchronized( mutex ) { list.fill( val ); } + } + public void fill( int fromIndex, int toIndex, float val ) { + synchronized( mutex ) { list.fill( fromIndex, toIndex, val ); } + } + + public void reverse() { + synchronized( mutex ) { list.reverse(); } + } + public void reverse( int from, int to ) { + synchronized( mutex ) { list.reverse( from, to ); } + } + + public void shuffle( Random rand ) { + synchronized( mutex ) { list.shuffle( rand ); } + } + + public void sort() { + synchronized( mutex ) { list.sort(); } + } + public void sort( int fromIndex, int toIndex ) { + synchronized( mutex ) { list.sort( fromIndex, toIndex ); } + } + + public int binarySearch( float value ) { + synchronized( mutex ) { return list.binarySearch( value ); } + } + public int binarySearch( float value, int fromIndex, int toIndex ) { + synchronized( mutex ) { return list.binarySearch( value, fromIndex, toIndex ); } + } + + public TFloatList grep( TFloatProcedure condition ) { + synchronized( mutex ) { return list.grep( condition ); } + } + public TFloatList inverseGrep( TFloatProcedure condition ) { + synchronized( mutex ) { return list.inverseGrep( condition ); } + } + + public float max() { synchronized( mutex ) { return list.max(); } } + public float min() { synchronized( mutex ) { return list.min(); } } + public float sum() { synchronized( mutex ) { return list.sum(); } } + + public boolean forEachDescending( TFloatProcedure procedure ) { + synchronized( mutex ) { return list.forEachDescending( procedure ); } + } + + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { list.transformValues( function ); } + } + + /** + * SynchronizedRandomAccessList instances are serialized as + * SynchronizedList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * SynchronizedList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, SynchronizedRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * SynchronizedList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TSynchronizedRandomAccessFloatList( list ) + : this ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatLongMap.java new file mode 100644 index 0000000..bd92042 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatLongMap implements TFloatLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatLongMap( TFloatLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatLongMap( TFloatLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( float key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient TLongCollection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( float key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( float key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( float key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( float key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatObjectMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatObjectMap.java new file mode 100644 index 0000000..fea1d0a --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatObjectMap.java @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import java.util.Collection; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatObjectMap + implements TFloatObjectMap, Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatObjectMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatObjectMap( TFloatObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatObjectMap( TFloatObjectMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( Object value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public V get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public V put( float key, V value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public V remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatObjectMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient Collection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public Collection valueCollection() { + synchronized( mutex ) { + if ( values == null ) { + values = new SynchronizedCollection( m.valueCollection(), mutex ); + } + return values; + } + } + public Object[] values() { + synchronized( mutex ) { return m.values(); } + } + public V[] values( V[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatObjectIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + + public V putIfAbsent( float key, V value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TObjectFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatObjectProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatSet.java b/src/gnu/trove/impl/sync/TSynchronizedFloatSet.java new file mode 100644 index 0000000..f338029 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatSet.java @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; + + +public class TSynchronizedFloatSet extends TSynchronizedFloatCollection + implements TFloatSet { + + private static final long serialVersionUID = 487447009682186044L; + + public TSynchronizedFloatSet( TFloatSet s ) { + super( s ); + } + public TSynchronizedFloatSet( TFloatSet s, Object mutex ) { + super( s, mutex ); + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return c.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return c.hashCode(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedFloatShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedFloatShortMap.java new file mode 100644 index 0000000..8bc71e6 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedFloatShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedFloatShortMap implements TFloatShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TFloatShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedFloatShortMap( TFloatShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedFloatShortMap( TFloatShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( float key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( float key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( float key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( float key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TFloatShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TFloatSet keySet = null; + private transient TShortCollection values = null; + + public TFloatSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedFloatSet( m.keySet(), mutex ); + return keySet; + } + } + public float[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public float[] keys( float[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TFloatShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public float getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( float key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TFloatShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TFloatShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( float key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( float key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( float key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntByteMap.java new file mode 100644 index 0000000..222bd1d --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntByteMap implements TIntByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntByteMap( TIntByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntByteMap( TIntByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( int key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient TByteCollection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( int key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( int key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( int key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( int key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntCharMap.java new file mode 100644 index 0000000..759c4e7 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntCharMap implements TIntCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntCharMap( TIntCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntCharMap( TIntCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( int key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient TCharCollection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( int key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( int key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( int key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( int key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntCollection.java b/src/gnu/trove/impl/sync/TSynchronizedIntCollection.java new file mode 100644 index 0000000..661894b --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntCollection.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntCollection implements TIntCollection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final TIntCollection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntCollection( TIntCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + mutex = this; + } + public TSynchronizedIntCollection( TIntCollection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( int o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public int[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + public int[] toArray( int[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public TIntIterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( int e ) { + synchronized (mutex ) { return c.add( e ); } + } + public boolean remove( int o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( TIntCollection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( int[] array ) { + synchronized( mutex ) { return c.containsAll( array );} + } + + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( TIntCollection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( int[] array ) { + synchronized( mutex ) { return c.addAll( array ); } + } + + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( TIntCollection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( int[] array ) { + synchronized( mutex ) { return c.removeAll( array ); } + } + + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( TIntCollection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( int[] array ) { + synchronized( mutex ) { return c.retainAll( array ); } + } + + public int getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TIntProcedure procedure ) { + synchronized( mutex ) { return c.forEach( procedure ); } + } + + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntDoubleMap.java new file mode 100644 index 0000000..954bb73 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntDoubleMap implements TIntDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntDoubleMap( TIntDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntDoubleMap( TIntDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( int key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient TDoubleCollection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( int key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( int key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( int key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( int key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntFloatMap.java new file mode 100644 index 0000000..264fb1e --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntFloatMap implements TIntFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntFloatMap( TIntFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntFloatMap( TIntFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( int key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient TFloatCollection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( int key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( int key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( int key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( int key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntIntMap.java new file mode 100644 index 0000000..097a578 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntIntMap implements TIntIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntIntMap( TIntIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntIntMap( TIntIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( int key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient TIntCollection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( int key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( int key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( int key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( int key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntList.java b/src/gnu/trove/impl/sync/TSynchronizedIntList.java new file mode 100644 index 0000000..fba786a --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntList.java @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TSynchronizedIntList extends TSynchronizedIntCollection + implements TIntList { + + static final long serialVersionUID = -7754090372962971524L; + + final TIntList list; + + public TSynchronizedIntList( TIntList list ) { + super( list ); + this.list = list; + } + public TSynchronizedIntList( TIntList list, Object mutex ) { + super( list, mutex ); + this.list = list; + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return list.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return list.hashCode(); } + } + + public int get( int index ) { + synchronized( mutex ) { return list.get( index ); } + } + public int set( int index, int element) { + synchronized( mutex ) { return list.set( index, element ); } + } + public void set( int offset, int[] values ) { + synchronized( mutex ) { list.set( offset, values ); } + } + public void set( int offset, int[] values, int valOffset, int length ) { + synchronized( mutex ) { list.set( offset, values, valOffset, length ); } + } + + public int replace( int offset, int val ) { + synchronized( mutex ) { return list.replace( offset, val ); } + } + public void remove( int offset, int length ) { + synchronized( mutex ) { list.remove( offset, length ); } + } + public int removeAt( int offset ) { + synchronized( mutex ) { return list.removeAt( offset ); } + } + + public void add( int[] vals ) { + synchronized( mutex ) { list.add( vals ); } + } + public void add( int[] vals, int offset, int length ) { + synchronized( mutex ) { list.add( vals, offset, length ); } + } + + public void insert( int offset, int value ) { + synchronized( mutex ) { list.insert( offset, value ); } + } + public void insert( int offset, int[] values ) { + synchronized( mutex ) { list.insert( offset, values ); } + } + public void insert( int offset, int[] values, int valOffset, int len ) { + synchronized( mutex ) { list.insert( offset, values, valOffset, len ); } + } + + public int indexOf( int o ) { + synchronized( mutex ) { return list.indexOf( o ); } + } + public int lastIndexOf( int o ) { + synchronized( mutex ) { return list.lastIndexOf( o ); } + } + +// public TListIntIterator listIterator() { +// return list.listIterator(); // Must be manually synched by user +// } + +// public TListIntIterator listIterator( int index ) { +// return list.listIterator( index ); // Must be manually synched by user +// } + + public TIntList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedIntList( list.subList( fromIndex, toIndex ), + mutex ); + } + } + + public int[] toArray( int offset, int len ) { + synchronized( mutex ) { return list.toArray( offset, len ); } + } + public int[] toArray( int[] dest, int offset, int len ) { + synchronized( mutex ) { return list.toArray( dest, offset, len ); } + } + public int[] toArray( int[] dest, int source_pos, int dest_pos, int len ) { + synchronized( mutex ) { return list.toArray( dest, source_pos, dest_pos, len ); } + } + + public int indexOf( int offset, int value ) { + synchronized( mutex ) { return list.indexOf( offset, value ); } + } + public int lastIndexOf( int offset, int value ) { + synchronized( mutex ) { return list.lastIndexOf( offset, value ); } + } + + public void fill( int val ) { + synchronized( mutex ) { list.fill( val ); } + } + public void fill( int fromIndex, int toIndex, int val ) { + synchronized( mutex ) { list.fill( fromIndex, toIndex, val ); } + } + + public void reverse() { + synchronized( mutex ) { list.reverse(); } + } + public void reverse( int from, int to ) { + synchronized( mutex ) { list.reverse( from, to ); } + } + + public void shuffle( Random rand ) { + synchronized( mutex ) { list.shuffle( rand ); } + } + + public void sort() { + synchronized( mutex ) { list.sort(); } + } + public void sort( int fromIndex, int toIndex ) { + synchronized( mutex ) { list.sort( fromIndex, toIndex ); } + } + + public int binarySearch( int value ) { + synchronized( mutex ) { return list.binarySearch( value ); } + } + public int binarySearch( int value, int fromIndex, int toIndex ) { + synchronized( mutex ) { return list.binarySearch( value, fromIndex, toIndex ); } + } + + public TIntList grep( TIntProcedure condition ) { + synchronized( mutex ) { return list.grep( condition ); } + } + public TIntList inverseGrep( TIntProcedure condition ) { + synchronized( mutex ) { return list.inverseGrep( condition ); } + } + + public int max() { synchronized( mutex ) { return list.max(); } } + public int min() { synchronized( mutex ) { return list.min(); } } + public int sum() { synchronized( mutex ) { return list.sum(); } } + + public boolean forEachDescending( TIntProcedure procedure ) { + synchronized( mutex ) { return list.forEachDescending( procedure ); } + } + + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { list.transformValues( function ); } + } + + /** + * SynchronizedRandomAccessList instances are serialized as + * SynchronizedList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * SynchronizedList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, SynchronizedRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * SynchronizedList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TSynchronizedRandomAccessIntList( list ) + : this ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntLongMap.java new file mode 100644 index 0000000..6d1711a --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntLongMap implements TIntLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntLongMap( TIntLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntLongMap( TIntLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( int key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient TLongCollection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( int key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( int key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( int key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( int key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntObjectMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntObjectMap.java new file mode 100644 index 0000000..addfd84 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntObjectMap.java @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import java.util.Collection; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntObjectMap + implements TIntObjectMap, Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntObjectMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntObjectMap( TIntObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntObjectMap( TIntObjectMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( Object value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public V get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public V put( int key, V value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public V remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntObjectMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient Collection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public Collection valueCollection() { + synchronized( mutex ) { + if ( values == null ) { + values = new SynchronizedCollection( m.valueCollection(), mutex ); + } + return values; + } + } + public Object[] values() { + synchronized( mutex ) { return m.values(); } + } + public V[] values( V[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntObjectIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + + public V putIfAbsent( int key, V value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TObjectFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntObjectProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntSet.java b/src/gnu/trove/impl/sync/TSynchronizedIntSet.java new file mode 100644 index 0000000..b719fd9 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntSet.java @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; + + +public class TSynchronizedIntSet extends TSynchronizedIntCollection + implements TIntSet { + + private static final long serialVersionUID = 487447009682186044L; + + public TSynchronizedIntSet( TIntSet s ) { + super( s ); + } + public TSynchronizedIntSet( TIntSet s, Object mutex ) { + super( s, mutex ); + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return c.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return c.hashCode(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedIntShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedIntShortMap.java new file mode 100644 index 0000000..49eaf54 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedIntShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedIntShortMap implements TIntShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TIntShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedIntShortMap( TIntShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedIntShortMap( TIntShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( int key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( int key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( int key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( int key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TIntShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TIntSet keySet = null; + private transient TShortCollection values = null; + + public TIntSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedIntSet( m.keySet(), mutex ); + return keySet; + } + } + public int[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public int[] keys( int[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TIntShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public int getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( int key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TIntShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TIntShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( int key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( int key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( int key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongByteMap.java new file mode 100644 index 0000000..2f4711c --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongByteMap implements TLongByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongByteMap( TLongByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongByteMap( TLongByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( long key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient TByteCollection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( long key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( long key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( long key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( long key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongCharMap.java new file mode 100644 index 0000000..272b7db --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongCharMap implements TLongCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongCharMap( TLongCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongCharMap( TLongCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( long key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient TCharCollection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( long key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( long key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( long key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( long key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongCollection.java b/src/gnu/trove/impl/sync/TSynchronizedLongCollection.java new file mode 100644 index 0000000..b310790 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongCollection.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongCollection implements TLongCollection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final TLongCollection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongCollection( TLongCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + mutex = this; + } + public TSynchronizedLongCollection( TLongCollection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( long o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public long[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + public long[] toArray( long[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public TLongIterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( long e ) { + synchronized (mutex ) { return c.add( e ); } + } + public boolean remove( long o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( TLongCollection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( long[] array ) { + synchronized( mutex ) { return c.containsAll( array );} + } + + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( TLongCollection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( long[] array ) { + synchronized( mutex ) { return c.addAll( array ); } + } + + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( TLongCollection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( long[] array ) { + synchronized( mutex ) { return c.removeAll( array ); } + } + + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( TLongCollection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( long[] array ) { + synchronized( mutex ) { return c.retainAll( array ); } + } + + public long getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TLongProcedure procedure ) { + synchronized( mutex ) { return c.forEach( procedure ); } + } + + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongDoubleMap.java new file mode 100644 index 0000000..c10bca0 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongDoubleMap implements TLongDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongDoubleMap( TLongDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongDoubleMap( TLongDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( long key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient TDoubleCollection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( long key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( long key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( long key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( long key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongFloatMap.java new file mode 100644 index 0000000..5d51194 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongFloatMap implements TLongFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongFloatMap( TLongFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongFloatMap( TLongFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( long key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient TFloatCollection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( long key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( long key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( long key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( long key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongIntMap.java new file mode 100644 index 0000000..fe0c01f --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongIntMap implements TLongIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongIntMap( TLongIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongIntMap( TLongIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( long key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient TIntCollection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( long key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( long key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( long key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( long key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongList.java b/src/gnu/trove/impl/sync/TSynchronizedLongList.java new file mode 100644 index 0000000..86f1000 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongList.java @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TSynchronizedLongList extends TSynchronizedLongCollection + implements TLongList { + + static final long serialVersionUID = -7754090372962971524L; + + final TLongList list; + + public TSynchronizedLongList( TLongList list ) { + super( list ); + this.list = list; + } + public TSynchronizedLongList( TLongList list, Object mutex ) { + super( list, mutex ); + this.list = list; + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return list.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return list.hashCode(); } + } + + public long get( int index ) { + synchronized( mutex ) { return list.get( index ); } + } + public long set( int index, long element) { + synchronized( mutex ) { return list.set( index, element ); } + } + public void set( int offset, long[] values ) { + synchronized( mutex ) { list.set( offset, values ); } + } + public void set( int offset, long[] values, int valOffset, int length ) { + synchronized( mutex ) { list.set( offset, values, valOffset, length ); } + } + + public long replace( int offset, long val ) { + synchronized( mutex ) { return list.replace( offset, val ); } + } + public void remove( int offset, int length ) { + synchronized( mutex ) { list.remove( offset, length ); } + } + public long removeAt( int offset ) { + synchronized( mutex ) { return list.removeAt( offset ); } + } + + public void add( long[] vals ) { + synchronized( mutex ) { list.add( vals ); } + } + public void add( long[] vals, int offset, int length ) { + synchronized( mutex ) { list.add( vals, offset, length ); } + } + + public void insert( int offset, long value ) { + synchronized( mutex ) { list.insert( offset, value ); } + } + public void insert( int offset, long[] values ) { + synchronized( mutex ) { list.insert( offset, values ); } + } + public void insert( int offset, long[] values, int valOffset, int len ) { + synchronized( mutex ) { list.insert( offset, values, valOffset, len ); } + } + + public int indexOf( long o ) { + synchronized( mutex ) { return list.indexOf( o ); } + } + public int lastIndexOf( long o ) { + synchronized( mutex ) { return list.lastIndexOf( o ); } + } + +// public TListLongIterator listIterator() { +// return list.listIterator(); // Must be manually synched by user +// } + +// public TListLongIterator listIterator( int index ) { +// return list.listIterator( index ); // Must be manually synched by user +// } + + public TLongList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedLongList( list.subList( fromIndex, toIndex ), + mutex ); + } + } + + public long[] toArray( int offset, int len ) { + synchronized( mutex ) { return list.toArray( offset, len ); } + } + public long[] toArray( long[] dest, int offset, int len ) { + synchronized( mutex ) { return list.toArray( dest, offset, len ); } + } + public long[] toArray( long[] dest, int source_pos, int dest_pos, int len ) { + synchronized( mutex ) { return list.toArray( dest, source_pos, dest_pos, len ); } + } + + public int indexOf( int offset, long value ) { + synchronized( mutex ) { return list.indexOf( offset, value ); } + } + public int lastIndexOf( int offset, long value ) { + synchronized( mutex ) { return list.lastIndexOf( offset, value ); } + } + + public void fill( long val ) { + synchronized( mutex ) { list.fill( val ); } + } + public void fill( int fromIndex, int toIndex, long val ) { + synchronized( mutex ) { list.fill( fromIndex, toIndex, val ); } + } + + public void reverse() { + synchronized( mutex ) { list.reverse(); } + } + public void reverse( int from, int to ) { + synchronized( mutex ) { list.reverse( from, to ); } + } + + public void shuffle( Random rand ) { + synchronized( mutex ) { list.shuffle( rand ); } + } + + public void sort() { + synchronized( mutex ) { list.sort(); } + } + public void sort( int fromIndex, int toIndex ) { + synchronized( mutex ) { list.sort( fromIndex, toIndex ); } + } + + public int binarySearch( long value ) { + synchronized( mutex ) { return list.binarySearch( value ); } + } + public int binarySearch( long value, int fromIndex, int toIndex ) { + synchronized( mutex ) { return list.binarySearch( value, fromIndex, toIndex ); } + } + + public TLongList grep( TLongProcedure condition ) { + synchronized( mutex ) { return list.grep( condition ); } + } + public TLongList inverseGrep( TLongProcedure condition ) { + synchronized( mutex ) { return list.inverseGrep( condition ); } + } + + public long max() { synchronized( mutex ) { return list.max(); } } + public long min() { synchronized( mutex ) { return list.min(); } } + public long sum() { synchronized( mutex ) { return list.sum(); } } + + public boolean forEachDescending( TLongProcedure procedure ) { + synchronized( mutex ) { return list.forEachDescending( procedure ); } + } + + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { list.transformValues( function ); } + } + + /** + * SynchronizedRandomAccessList instances are serialized as + * SynchronizedList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * SynchronizedList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, SynchronizedRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * SynchronizedList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TSynchronizedRandomAccessLongList( list ) + : this ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongLongMap.java new file mode 100644 index 0000000..43d1066 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongLongMap implements TLongLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongLongMap( TLongLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongLongMap( TLongLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( long key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient TLongCollection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( long key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( long key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( long key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( long key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongObjectMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongObjectMap.java new file mode 100644 index 0000000..18eea8d --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongObjectMap.java @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import java.util.Collection; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongObjectMap + implements TLongObjectMap, Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongObjectMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongObjectMap( TLongObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongObjectMap( TLongObjectMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( Object value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public V get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public V put( long key, V value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public V remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongObjectMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient Collection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public Collection valueCollection() { + synchronized( mutex ) { + if ( values == null ) { + values = new SynchronizedCollection( m.valueCollection(), mutex ); + } + return values; + } + } + public Object[] values() { + synchronized( mutex ) { return m.values(); } + } + public V[] values( V[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongObjectIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + + public V putIfAbsent( long key, V value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TObjectFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongObjectProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongSet.java b/src/gnu/trove/impl/sync/TSynchronizedLongSet.java new file mode 100644 index 0000000..4fb13fd --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongSet.java @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; + + +public class TSynchronizedLongSet extends TSynchronizedLongCollection + implements TLongSet { + + private static final long serialVersionUID = 487447009682186044L; + + public TSynchronizedLongSet( TLongSet s ) { + super( s ); + } + public TSynchronizedLongSet( TLongSet s, Object mutex ) { + super( s, mutex ); + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return c.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return c.hashCode(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedLongShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedLongShortMap.java new file mode 100644 index 0000000..8cf6e9d --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedLongShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedLongShortMap implements TLongShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TLongShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedLongShortMap( TLongShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedLongShortMap( TLongShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( long key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( long key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( long key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( long key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TLongShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TLongSet keySet = null; + private transient TShortCollection values = null; + + public TLongSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedLongSet( m.keySet(), mutex ); + return keySet; + } + } + public long[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public long[] keys( long[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TLongShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public long getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( long key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TLongShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TLongShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( long key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( long key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( long key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedObjectByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedObjectByteMap.java new file mode 100644 index 0000000..39dd302 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedObjectByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Set; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedObjectByteMap implements TObjectByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TObjectByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedObjectByteMap( TObjectByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedObjectByteMap( TObjectByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( Object key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( Object key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( K key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( Object key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TObjectByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient Set keySet = null; + private transient TByteCollection values = null; + + public Set keySet() { + synchronized( mutex ) { + if ( keySet == null ) { + keySet = new SynchronizedSet( m.keySet(), mutex ); + } + return keySet; + } + } + public Object[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public K[] keys( K[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TObjectByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( K key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TObjectByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TObjectByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( K key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( K key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( K key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedObjectCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedObjectCharMap.java new file mode 100644 index 0000000..569513c --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedObjectCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Set; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedObjectCharMap implements TObjectCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TObjectCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedObjectCharMap( TObjectCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedObjectCharMap( TObjectCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( Object key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( Object key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( K key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( Object key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TObjectCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient Set keySet = null; + private transient TCharCollection values = null; + + public Set keySet() { + synchronized( mutex ) { + if ( keySet == null ) { + keySet = new SynchronizedSet( m.keySet(), mutex ); + } + return keySet; + } + } + public Object[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public K[] keys( K[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TObjectCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( K key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TObjectCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TObjectCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( K key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( K key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( K key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedObjectDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedObjectDoubleMap.java new file mode 100644 index 0000000..ec28f51 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedObjectDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Set; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedObjectDoubleMap implements TObjectDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TObjectDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedObjectDoubleMap( TObjectDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedObjectDoubleMap( TObjectDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( Object key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( Object key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( K key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( Object key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TObjectDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient Set keySet = null; + private transient TDoubleCollection values = null; + + public Set keySet() { + synchronized( mutex ) { + if ( keySet == null ) { + keySet = new SynchronizedSet( m.keySet(), mutex ); + } + return keySet; + } + } + public Object[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public K[] keys( K[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TObjectDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( K key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TObjectDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TObjectDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( K key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( K key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( K key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedObjectFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedObjectFloatMap.java new file mode 100644 index 0000000..fb70bb8 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedObjectFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Set; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedObjectFloatMap implements TObjectFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TObjectFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedObjectFloatMap( TObjectFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedObjectFloatMap( TObjectFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( Object key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( Object key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( K key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( Object key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TObjectFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient Set keySet = null; + private transient TFloatCollection values = null; + + public Set keySet() { + synchronized( mutex ) { + if ( keySet == null ) { + keySet = new SynchronizedSet( m.keySet(), mutex ); + } + return keySet; + } + } + public Object[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public K[] keys( K[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TObjectFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( K key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TObjectFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TObjectFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( K key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( K key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( K key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedObjectIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedObjectIntMap.java new file mode 100644 index 0000000..9fc7647 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedObjectIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Set; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedObjectIntMap implements TObjectIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TObjectIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedObjectIntMap( TObjectIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedObjectIntMap( TObjectIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( Object key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( Object key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( K key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( Object key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TObjectIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient Set keySet = null; + private transient TIntCollection values = null; + + public Set keySet() { + synchronized( mutex ) { + if ( keySet == null ) { + keySet = new SynchronizedSet( m.keySet(), mutex ); + } + return keySet; + } + } + public Object[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public K[] keys( K[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TObjectIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( K key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TObjectIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TObjectIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( K key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( K key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( K key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedObjectLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedObjectLongMap.java new file mode 100644 index 0000000..1130884 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedObjectLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Set; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedObjectLongMap implements TObjectLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TObjectLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedObjectLongMap( TObjectLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedObjectLongMap( TObjectLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( Object key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( Object key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( K key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( Object key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TObjectLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient Set keySet = null; + private transient TLongCollection values = null; + + public Set keySet() { + synchronized( mutex ) { + if ( keySet == null ) { + keySet = new SynchronizedSet( m.keySet(), mutex ); + } + return keySet; + } + } + public Object[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public K[] keys( K[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TObjectLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( K key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TObjectLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TObjectLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( K key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( K key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( K key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedObjectShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedObjectShortMap.java new file mode 100644 index 0000000..2a0ed0b --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedObjectShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Set; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedObjectShortMap implements TObjectShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TObjectShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedObjectShortMap( TObjectShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedObjectShortMap( TObjectShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( Object key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( Object key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( K key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( Object key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TObjectShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient Set keySet = null; + private transient TShortCollection values = null; + + public Set keySet() { + synchronized( mutex ) { + if ( keySet == null ) { + keySet = new SynchronizedSet( m.keySet(), mutex ); + } + return keySet; + } + } + public Object[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public K[] keys( K[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TObjectShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( K key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TObjectShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TObjectShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( K key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( K key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( K key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedRandomAccessByteList.java b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessByteList.java new file mode 100644 index 0000000..918116d --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessByteList.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TSynchronizedRandomAccessByteList extends TSynchronizedByteList + implements RandomAccess { + + static final long serialVersionUID = 1530674583602358482L; + + public TSynchronizedRandomAccessByteList( TByteList list ) { + super( list ); + } + + public TSynchronizedRandomAccessByteList( TByteList list, Object mutex ) { + super( list, mutex ); + } + + public TByteList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedRandomAccessByteList( + list.subList( fromIndex, toIndex ), mutex ); + } + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have SynchronizedRandomAccessList). SynchronizedList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TSynchronizedByteList( list ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedRandomAccessCharList.java b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessCharList.java new file mode 100644 index 0000000..6ef91b2 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessCharList.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TSynchronizedRandomAccessCharList extends TSynchronizedCharList + implements RandomAccess { + + static final long serialVersionUID = 1530674583602358482L; + + public TSynchronizedRandomAccessCharList( TCharList list ) { + super( list ); + } + + public TSynchronizedRandomAccessCharList( TCharList list, Object mutex ) { + super( list, mutex ); + } + + public TCharList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedRandomAccessCharList( + list.subList( fromIndex, toIndex ), mutex ); + } + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have SynchronizedRandomAccessList). SynchronizedList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TSynchronizedCharList( list ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedRandomAccessDoubleList.java b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessDoubleList.java new file mode 100644 index 0000000..5c2d5f2 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessDoubleList.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TSynchronizedRandomAccessDoubleList extends TSynchronizedDoubleList + implements RandomAccess { + + static final long serialVersionUID = 1530674583602358482L; + + public TSynchronizedRandomAccessDoubleList( TDoubleList list ) { + super( list ); + } + + public TSynchronizedRandomAccessDoubleList( TDoubleList list, Object mutex ) { + super( list, mutex ); + } + + public TDoubleList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedRandomAccessDoubleList( + list.subList( fromIndex, toIndex ), mutex ); + } + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have SynchronizedRandomAccessList). SynchronizedList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TSynchronizedDoubleList( list ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedRandomAccessFloatList.java b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessFloatList.java new file mode 100644 index 0000000..fcfc83a --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessFloatList.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TSynchronizedRandomAccessFloatList extends TSynchronizedFloatList + implements RandomAccess { + + static final long serialVersionUID = 1530674583602358482L; + + public TSynchronizedRandomAccessFloatList( TFloatList list ) { + super( list ); + } + + public TSynchronizedRandomAccessFloatList( TFloatList list, Object mutex ) { + super( list, mutex ); + } + + public TFloatList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedRandomAccessFloatList( + list.subList( fromIndex, toIndex ), mutex ); + } + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have SynchronizedRandomAccessList). SynchronizedList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TSynchronizedFloatList( list ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedRandomAccessIntList.java b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessIntList.java new file mode 100644 index 0000000..7f82869 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessIntList.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TSynchronizedRandomAccessIntList extends TSynchronizedIntList + implements RandomAccess { + + static final long serialVersionUID = 1530674583602358482L; + + public TSynchronizedRandomAccessIntList( TIntList list ) { + super( list ); + } + + public TSynchronizedRandomAccessIntList( TIntList list, Object mutex ) { + super( list, mutex ); + } + + public TIntList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedRandomAccessIntList( + list.subList( fromIndex, toIndex ), mutex ); + } + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have SynchronizedRandomAccessList). SynchronizedList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TSynchronizedIntList( list ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedRandomAccessLongList.java b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessLongList.java new file mode 100644 index 0000000..bcd9c5e --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessLongList.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TSynchronizedRandomAccessLongList extends TSynchronizedLongList + implements RandomAccess { + + static final long serialVersionUID = 1530674583602358482L; + + public TSynchronizedRandomAccessLongList( TLongList list ) { + super( list ); + } + + public TSynchronizedRandomAccessLongList( TLongList list, Object mutex ) { + super( list, mutex ); + } + + public TLongList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedRandomAccessLongList( + list.subList( fromIndex, toIndex ), mutex ); + } + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have SynchronizedRandomAccessList). SynchronizedList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TSynchronizedLongList( list ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedRandomAccessShortList.java b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessShortList.java new file mode 100644 index 0000000..d62fbd4 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedRandomAccessShortList.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TSynchronizedRandomAccessShortList extends TSynchronizedShortList + implements RandomAccess { + + static final long serialVersionUID = 1530674583602358482L; + + public TSynchronizedRandomAccessShortList( TShortList list ) { + super( list ); + } + + public TSynchronizedRandomAccessShortList( TShortList list, Object mutex ) { + super( list, mutex ); + } + + public TShortList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedRandomAccessShortList( + list.subList( fromIndex, toIndex ), mutex ); + } + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have SynchronizedRandomAccessList). SynchronizedList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TSynchronizedShortList( list ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortByteMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortByteMap.java new file mode 100644 index 0000000..15d4f4b --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortByteMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortByteMap implements TShortByteMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortByteMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortByteMap( TShortByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortByteMap( TShortByteMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( byte value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public byte get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public byte put( short key, byte value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public byte remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortByteMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient TByteCollection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TByteCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedByteCollection( m.valueCollection(), mutex ); + return values; + } + } + public byte[] values() { + synchronized( mutex ) { return m.values(); } + } + public byte[] values( byte[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortByteIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public byte putIfAbsent( short key, byte value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortByteProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TByteFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortByteProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( short key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( short key, byte amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public byte adjustOrPutValue( short key, byte adjust_amount, byte put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortCharMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortCharMap.java new file mode 100644 index 0000000..5203c6f --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortCharMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortCharMap implements TShortCharMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortCharMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortCharMap( TShortCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortCharMap( TShortCharMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( char value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public char get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public char put( short key, char value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public char remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortCharMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient TCharCollection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TCharCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedCharCollection( m.valueCollection(), mutex ); + return values; + } + } + public char[] values() { + synchronized( mutex ) { return m.values(); } + } + public char[] values( char[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortCharIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public char putIfAbsent( short key, char value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortCharProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TCharFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortCharProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( short key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( short key, char amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public char adjustOrPutValue( short key, char adjust_amount, char put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortCollection.java b/src/gnu/trove/impl/sync/TSynchronizedShortCollection.java new file mode 100644 index 0000000..eea1200 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortCollection.java @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortCollection implements TShortCollection, Serializable { + private static final long serialVersionUID = 3053995032091335093L; + + final TShortCollection c; // Backing Collection + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortCollection( TShortCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + mutex = this; + } + public TSynchronizedShortCollection( TShortCollection c, Object mutex ) { + this.c = c; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return c.size(); } + } + public boolean isEmpty() { + synchronized( mutex ) { return c.isEmpty(); } + } + public boolean contains( short o ) { + synchronized( mutex ) { return c.contains( o ); } + } + public short[] toArray() { + synchronized( mutex ) { return c.toArray(); } + } + public short[] toArray( short[] a ) { + synchronized( mutex ) { return c.toArray( a ); } + } + + public TShortIterator iterator() { + return c.iterator(); // Must be manually synched by user! + } + + public boolean add( short e ) { + synchronized (mutex ) { return c.add( e ); } + } + public boolean remove( short o ) { + synchronized( mutex ) { return c.remove( o ); } + } + + public boolean containsAll( Collection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( TShortCollection coll ) { + synchronized( mutex ) { return c.containsAll( coll );} + } + public boolean containsAll( short[] array ) { + synchronized( mutex ) { return c.containsAll( array );} + } + + public boolean addAll( Collection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( TShortCollection coll ) { + synchronized( mutex ) { return c.addAll( coll ); } + } + public boolean addAll( short[] array ) { + synchronized( mutex ) { return c.addAll( array ); } + } + + public boolean removeAll( Collection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( TShortCollection coll ) { + synchronized( mutex ) { return c.removeAll( coll ); } + } + public boolean removeAll( short[] array ) { + synchronized( mutex ) { return c.removeAll( array ); } + } + + public boolean retainAll( Collection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( TShortCollection coll ) { + synchronized( mutex ) { return c.retainAll( coll ); } + } + public boolean retainAll( short[] array ) { + synchronized( mutex ) { return c.retainAll( array ); } + } + + public short getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TShortProcedure procedure ) { + synchronized( mutex ) { return c.forEach( procedure ); } + } + + public void clear() { + synchronized( mutex ) { c.clear(); } + } + public String toString() { + synchronized( mutex ) { return c.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortDoubleMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortDoubleMap.java new file mode 100644 index 0000000..3bfce9a --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortDoubleMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortDoubleMap implements TShortDoubleMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortDoubleMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortDoubleMap( TShortDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortDoubleMap( TShortDoubleMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( double value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public double get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public double put( short key, double value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public double remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortDoubleMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient TDoubleCollection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TDoubleCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedDoubleCollection( m.valueCollection(), mutex ); + return values; + } + } + public double[] values() { + synchronized( mutex ) { return m.values(); } + } + public double[] values( double[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortDoubleIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public double putIfAbsent( short key, double value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortDoubleProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TDoubleFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortDoubleProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( short key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( short key, double amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public double adjustOrPutValue( short key, double adjust_amount, double put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortFloatMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortFloatMap.java new file mode 100644 index 0000000..1080e1c --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortFloatMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortFloatMap implements TShortFloatMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortFloatMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortFloatMap( TShortFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortFloatMap( TShortFloatMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( float value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public float get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public float put( short key, float value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public float remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortFloatMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient TFloatCollection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TFloatCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedFloatCollection( m.valueCollection(), mutex ); + return values; + } + } + public float[] values() { + synchronized( mutex ) { return m.values(); } + } + public float[] values( float[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortFloatIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public float putIfAbsent( short key, float value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortFloatProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TFloatFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortFloatProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( short key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( short key, float amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public float adjustOrPutValue( short key, float adjust_amount, float put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortIntMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortIntMap.java new file mode 100644 index 0000000..2490b9b --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortIntMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortIntMap implements TShortIntMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortIntMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortIntMap( TShortIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortIntMap( TShortIntMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( int value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public int get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public int put( short key, int value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public int remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortIntMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient TIntCollection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TIntCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedIntCollection( m.valueCollection(), mutex ); + return values; + } + } + public int[] values() { + synchronized( mutex ) { return m.values(); } + } + public int[] values( int[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortIntIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public int putIfAbsent( short key, int value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortIntProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TIntFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortIntProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( short key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( short key, int amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public int adjustOrPutValue( short key, int adjust_amount, int put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortList.java b/src/gnu/trove/impl/sync/TSynchronizedShortList.java new file mode 100644 index 0000000..1c4ad64 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortList.java @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TSynchronizedShortList extends TSynchronizedShortCollection + implements TShortList { + + static final long serialVersionUID = -7754090372962971524L; + + final TShortList list; + + public TSynchronizedShortList( TShortList list ) { + super( list ); + this.list = list; + } + public TSynchronizedShortList( TShortList list, Object mutex ) { + super( list, mutex ); + this.list = list; + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return list.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return list.hashCode(); } + } + + public short get( int index ) { + synchronized( mutex ) { return list.get( index ); } + } + public short set( int index, short element) { + synchronized( mutex ) { return list.set( index, element ); } + } + public void set( int offset, short[] values ) { + synchronized( mutex ) { list.set( offset, values ); } + } + public void set( int offset, short[] values, int valOffset, int length ) { + synchronized( mutex ) { list.set( offset, values, valOffset, length ); } + } + + public short replace( int offset, short val ) { + synchronized( mutex ) { return list.replace( offset, val ); } + } + public void remove( int offset, int length ) { + synchronized( mutex ) { list.remove( offset, length ); } + } + public short removeAt( int offset ) { + synchronized( mutex ) { return list.removeAt( offset ); } + } + + public void add( short[] vals ) { + synchronized( mutex ) { list.add( vals ); } + } + public void add( short[] vals, int offset, int length ) { + synchronized( mutex ) { list.add( vals, offset, length ); } + } + + public void insert( int offset, short value ) { + synchronized( mutex ) { list.insert( offset, value ); } + } + public void insert( int offset, short[] values ) { + synchronized( mutex ) { list.insert( offset, values ); } + } + public void insert( int offset, short[] values, int valOffset, int len ) { + synchronized( mutex ) { list.insert( offset, values, valOffset, len ); } + } + + public int indexOf( short o ) { + synchronized( mutex ) { return list.indexOf( o ); } + } + public int lastIndexOf( short o ) { + synchronized( mutex ) { return list.lastIndexOf( o ); } + } + +// public TListShortIterator listIterator() { +// return list.listIterator(); // Must be manually synched by user +// } + +// public TListShortIterator listIterator( int index ) { +// return list.listIterator( index ); // Must be manually synched by user +// } + + public TShortList subList( int fromIndex, int toIndex ) { + synchronized( mutex ) { + return new TSynchronizedShortList( list.subList( fromIndex, toIndex ), + mutex ); + } + } + + public short[] toArray( int offset, int len ) { + synchronized( mutex ) { return list.toArray( offset, len ); } + } + public short[] toArray( short[] dest, int offset, int len ) { + synchronized( mutex ) { return list.toArray( dest, offset, len ); } + } + public short[] toArray( short[] dest, int source_pos, int dest_pos, int len ) { + synchronized( mutex ) { return list.toArray( dest, source_pos, dest_pos, len ); } + } + + public int indexOf( int offset, short value ) { + synchronized( mutex ) { return list.indexOf( offset, value ); } + } + public int lastIndexOf( int offset, short value ) { + synchronized( mutex ) { return list.lastIndexOf( offset, value ); } + } + + public void fill( short val ) { + synchronized( mutex ) { list.fill( val ); } + } + public void fill( int fromIndex, int toIndex, short val ) { + synchronized( mutex ) { list.fill( fromIndex, toIndex, val ); } + } + + public void reverse() { + synchronized( mutex ) { list.reverse(); } + } + public void reverse( int from, int to ) { + synchronized( mutex ) { list.reverse( from, to ); } + } + + public void shuffle( Random rand ) { + synchronized( mutex ) { list.shuffle( rand ); } + } + + public void sort() { + synchronized( mutex ) { list.sort(); } + } + public void sort( int fromIndex, int toIndex ) { + synchronized( mutex ) { list.sort( fromIndex, toIndex ); } + } + + public int binarySearch( short value ) { + synchronized( mutex ) { return list.binarySearch( value ); } + } + public int binarySearch( short value, int fromIndex, int toIndex ) { + synchronized( mutex ) { return list.binarySearch( value, fromIndex, toIndex ); } + } + + public TShortList grep( TShortProcedure condition ) { + synchronized( mutex ) { return list.grep( condition ); } + } + public TShortList inverseGrep( TShortProcedure condition ) { + synchronized( mutex ) { return list.inverseGrep( condition ); } + } + + public short max() { synchronized( mutex ) { return list.max(); } } + public short min() { synchronized( mutex ) { return list.min(); } } + public short sum() { synchronized( mutex ) { return list.sum(); } } + + public boolean forEachDescending( TShortProcedure procedure ) { + synchronized( mutex ) { return list.forEachDescending( procedure ); } + } + + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { list.transformValues( function ); } + } + + /** + * SynchronizedRandomAccessList instances are serialized as + * SynchronizedList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * SynchronizedList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, SynchronizedRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * SynchronizedList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TSynchronizedRandomAccessShortList( list ) + : this ); + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortLongMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortLongMap.java new file mode 100644 index 0000000..6d98cd0 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortLongMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortLongMap implements TShortLongMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortLongMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortLongMap( TShortLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortLongMap( TShortLongMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( long value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public long get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public long put( short key, long value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public long remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortLongMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient TLongCollection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TLongCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedLongCollection( m.valueCollection(), mutex ); + return values; + } + } + public long[] values() { + synchronized( mutex ) { return m.values(); } + } + public long[] values( long[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortLongIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public long putIfAbsent( short key, long value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortLongProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TLongFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortLongProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( short key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( short key, long amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public long adjustOrPutValue( short key, long adjust_amount, long put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortObjectMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortObjectMap.java new file mode 100644 index 0000000..59f06fd --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortObjectMap.java @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import java.util.Collection; +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortObjectMap + implements TShortObjectMap, Serializable { + // use serialVersionUID from JDK 1.2.2 for interoperability + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortObjectMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortObjectMap( TShortObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortObjectMap( TShortObjectMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( Object value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public V get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public V put( short key, V value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public V remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortObjectMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient Collection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public Collection valueCollection() { + synchronized( mutex ) { + if ( values == null ) { + values = new SynchronizedCollection( m.valueCollection(), mutex ); + } + return values; + } + } + public Object[] values() { + synchronized( mutex ) { return m.values(); } + } + public V[] values( V[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortObjectIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + + public V putIfAbsent( short key, V value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortObjectProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TObjectFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortObjectProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortSet.java b/src/gnu/trove/impl/sync/TSynchronizedShortSet.java new file mode 100644 index 0000000..90432a8 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortSet.java @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; + + +public class TSynchronizedShortSet extends TSynchronizedShortCollection + implements TShortSet { + + private static final long serialVersionUID = 487447009682186044L; + + public TSynchronizedShortSet( TShortSet s ) { + super( s ); + } + public TSynchronizedShortSet( TShortSet s, Object mutex ) { + super( s, mutex ); + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return c.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return c.hashCode(); } + } +} diff --git a/src/gnu/trove/impl/sync/TSynchronizedShortShortMap.java b/src/gnu/trove/impl/sync/TSynchronizedShortShortMap.java new file mode 100644 index 0000000..3567f42 --- /dev/null +++ b/src/gnu/trove/impl/sync/TSynchronizedShortShortMap.java @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.sync; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.IOException; + + +public class TSynchronizedShortShortMap implements TShortShortMap, Serializable { + private static final long serialVersionUID = 1978198479659022715L; + + private final TShortShortMap m; // Backing Map + final Object mutex; // Object on which to synchronize + + public TSynchronizedShortShortMap( TShortShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + mutex = this; + } + + public TSynchronizedShortShortMap( TShortShortMap m, Object mutex ) { + this.m = m; + this.mutex = mutex; + } + + public int size() { + synchronized( mutex ) { return m.size(); } + } + public boolean isEmpty(){ + synchronized( mutex ) { return m.isEmpty(); } + } + public boolean containsKey( short key ) { + synchronized( mutex ) { return m.containsKey( key ); } + } + public boolean containsValue( short value ){ + synchronized( mutex ) { return m.containsValue( value ); } + } + public short get( short key ) { + synchronized( mutex ) { return m.get( key ); } + } + + public short put( short key, short value ) { + synchronized( mutex ) { return m.put( key, value ); } + } + public short remove( short key ) { + synchronized( mutex ) { return m.remove( key ); } + } + public void putAll( Map map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void putAll( TShortShortMap map ) { + synchronized( mutex ) { m.putAll( map ); } + } + public void clear() { + synchronized( mutex ) { m.clear(); } + } + + private transient TShortSet keySet = null; + private transient TShortCollection values = null; + + public TShortSet keySet() { + synchronized( mutex ) { + if ( keySet == null ) + keySet = new TSynchronizedShortSet( m.keySet(), mutex ); + return keySet; + } + } + public short[] keys() { + synchronized( mutex ) { return m.keys(); } + } + public short[] keys( short[] array ) { + synchronized( mutex ) { return m.keys( array ); } + } + + public TShortCollection valueCollection() { + synchronized( mutex ) { + if ( values == null ) + values = new TSynchronizedShortCollection( m.valueCollection(), mutex ); + return values; + } + } + public short[] values() { + synchronized( mutex ) { return m.values(); } + } + public short[] values( short[] array ) { + synchronized( mutex ) { return m.values( array ); } + } + + public TShortShortIterator iterator() { + return m.iterator(); // Must be manually synched by user! + } + + // these are unchanging over the life of the map, no need to lock + public short getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public short putIfAbsent( short key, short value ) { + synchronized( mutex ) { return m.putIfAbsent( key, value ); } + } + public boolean forEachKey( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachKey( procedure ); } + } + public boolean forEachValue( TShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachValue( procedure ); } + } + public boolean forEachEntry( TShortShortProcedure procedure ) { + synchronized( mutex ) { return m.forEachEntry( procedure ); } + } + public void transformValues( TShortFunction function ) { + synchronized( mutex ) { m.transformValues( function ); } + } + public boolean retainEntries( TShortShortProcedure procedure ) { + synchronized( mutex ) { return m.retainEntries( procedure ); } + } + public boolean increment( short key ) { + synchronized( mutex ) { return m.increment( key ); } + } + public boolean adjustValue( short key, short amount ) { + synchronized( mutex ) { return m.adjustValue( key, amount ); } + } + public short adjustOrPutValue( short key, short adjust_amount, short put_amount ) { + synchronized( mutex ) { return m.adjustOrPutValue( key, adjust_amount, put_amount ); } + } + + public boolean equals( Object o ) { + synchronized( mutex ) { return m.equals( o ); } + } + public int hashCode() { + synchronized( mutex ) { return m.hashCode(); } + } + public String toString() { + synchronized( mutex ) { return m.toString(); } + } + private void writeObject( ObjectOutputStream s ) throws IOException { + synchronized( mutex ) { s.defaultWriteObject(); } + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteByteMap.java new file mode 100644 index 0000000..c8cf306 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteByteMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableByteByteMap implements TByteByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteByteMap m; + + public TUnmodifiableByteByteMap( TByteByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( byte key) { return m.get( key ); } + + public byte put( byte key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient TByteCollection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteByteIterator iterator() { + return new TByteByteIterator() { + TByteByteIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( byte key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( byte key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( byte key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( byte key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteCharMap.java new file mode 100644 index 0000000..9bac067 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteCharMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableByteCharMap implements TByteCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteCharMap m; + + public TUnmodifiableByteCharMap( TByteCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( byte key) { return m.get( key ); } + + public char put( byte key, char value ) { throw new UnsupportedOperationException(); } + public char remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient TCharCollection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteCharIterator iterator() { + return new TByteCharIterator() { + TByteCharIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( byte key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( byte key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( byte key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( byte key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteCollection.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteCollection.java new file mode 100644 index 0000000..7de37e0 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteCollection.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; + + +public class TUnmodifiableByteCollection implements TByteCollection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; + + final TByteCollection c; + + public TUnmodifiableByteCollection( TByteCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + } + + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains( byte o ) { return c.contains( o ); } + public byte[] toArray() { return c.toArray(); } + public byte[] toArray( byte[] a ) { return c.toArray( a ); } + public String toString() { return c.toString(); } + public byte getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TByteProcedure procedure ) { return c.forEach( procedure ); } + + public TByteIterator iterator() { + return new TByteIterator() { + TByteIterator i = c.iterator(); + + public boolean hasNext() { return i.hasNext(); } + public byte next() { return i.next(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public boolean add( byte e ) { throw new UnsupportedOperationException(); } + public boolean remove( byte o ) { throw new UnsupportedOperationException(); } + + public boolean containsAll( Collection coll ) { return c.containsAll( coll ); } + public boolean containsAll( TByteCollection coll ) { return c.containsAll( coll ); } + public boolean containsAll( byte[] array ) { return c.containsAll( array ); } + + public boolean addAll( TByteCollection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( byte[] array ) { throw new UnsupportedOperationException(); } + + public boolean removeAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( TByteCollection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( byte[] array ) { throw new UnsupportedOperationException(); } + + public boolean retainAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( TByteCollection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( byte[] array ) { throw new UnsupportedOperationException(); } + + public void clear() { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteDoubleMap.java new file mode 100644 index 0000000..841636b --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteDoubleMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableByteDoubleMap implements TByteDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteDoubleMap m; + + public TUnmodifiableByteDoubleMap( TByteDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( byte key) { return m.get( key ); } + + public double put( byte key, double value ) { throw new UnsupportedOperationException(); } + public double remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient TDoubleCollection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteDoubleIterator iterator() { + return new TByteDoubleIterator() { + TByteDoubleIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( byte key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( byte key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( byte key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( byte key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteFloatMap.java new file mode 100644 index 0000000..f8cbec4 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteFloatMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableByteFloatMap implements TByteFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteFloatMap m; + + public TUnmodifiableByteFloatMap( TByteFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( byte key) { return m.get( key ); } + + public float put( byte key, float value ) { throw new UnsupportedOperationException(); } + public float remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient TFloatCollection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteFloatIterator iterator() { + return new TByteFloatIterator() { + TByteFloatIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( byte key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( byte key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( byte key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( byte key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteIntMap.java new file mode 100644 index 0000000..1355f70 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteIntMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableByteIntMap implements TByteIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteIntMap m; + + public TUnmodifiableByteIntMap( TByteIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( byte key) { return m.get( key ); } + + public int put( byte key, int value ) { throw new UnsupportedOperationException(); } + public int remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient TIntCollection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteIntIterator iterator() { + return new TByteIntIterator() { + TByteIntIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( byte key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( byte key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( byte key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( byte key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteList.java new file mode 100644 index 0000000..1f64171 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteList.java @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TUnmodifiableByteList extends TUnmodifiableByteCollection implements TByteList { + static final long serialVersionUID = -283967356065247728L; + + final TByteList list; + + public TUnmodifiableByteList( TByteList list ) { + super( list ); + this.list = list; + } + + public boolean equals( Object o ) { return o == this || list.equals( o ); } + public int hashCode() { return list.hashCode(); } + + public byte get( int index ) { return list.get( index ); } + public int indexOf( byte o ) { return list.indexOf( o ); } + public int lastIndexOf( byte o ) { return list.lastIndexOf( o ); } + + public byte[] toArray( int offset, int len ) { + return list.toArray( offset, len ); + } + public byte[] toArray( byte[] dest, int offset, int len ) { + return list.toArray( dest, offset, len ); + } + public byte[] toArray( byte[] dest, int source_pos, int dest_pos, int len ) { + return list.toArray( dest, source_pos, dest_pos, len ); + } + + public boolean forEachDescending( TByteProcedure procedure ) { + return list.forEachDescending( procedure ); + } + + public int binarySearch( byte value ) { return list.binarySearch( value ); } + public int binarySearch( byte value, int fromIndex, int toIndex ) { + return list.binarySearch( value, fromIndex, toIndex ); + } + + public int indexOf( int offset, byte value ) { return list.indexOf( offset, value ); } + public int lastIndexOf( int offset, byte value ) { return list.lastIndexOf( offset, value ); } + public TByteList grep( TByteProcedure condition ) { return list.grep( condition ); } + public TByteList inverseGrep( TByteProcedure condition ) { return list.inverseGrep( condition ); } + + public byte max() { return list.max(); } + public byte min() { return list.min(); } + public byte sum() { return list.sum(); } + + public TByteList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableByteList( list.subList( fromIndex, toIndex ) ); + } + + // TODO: Do we want to fullt implement ListIterator? +// public TIntListIterator listIterator() {return listIterator(0);} +// +// public ListIterator listIterator(final int index) { +// return new ListIterator() { +// ListIterator i = list.listIterator(index); +// +// public boolean hasNext() {return i.hasNext();} +// public E next() {return i.next();} +// public boolean hasPrevious() {return i.hasPrevious();} +// public E previous() {return i.previous();} +// public int nextIndex() {return i.nextIndex();} +// public int previousIndex() {return i.previousIndex();} +// +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// public void set(E e) { +// throw new UnsupportedOperationException(); +// } +// public void add(E e) { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + /** + * UnmodifiableRandomAccessList instances are serialized as + * UnmodifiableList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * UnmodifiableList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, UnmodifiableRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * UnmodifiableList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TUnmodifiableRandomAccessByteList( list ) + : this); + } + + public void add( byte[] vals ) { throw new UnsupportedOperationException(); } + public void add( byte[] vals, int offset, int length ) { throw new UnsupportedOperationException(); } + + public byte removeAt( int offset ) { throw new UnsupportedOperationException(); } + public void remove( int offset, int length ) { throw new UnsupportedOperationException(); } + + public void insert( int offset, byte value ) { throw new UnsupportedOperationException(); } + public void insert( int offset, byte[] values ) { throw new UnsupportedOperationException(); } + public void insert( int offset, byte[] values, int valOffset, int len ) { throw new UnsupportedOperationException(); } + + public byte set( int offset, byte val ) { throw new UnsupportedOperationException(); } + public void set( int offset, byte[] values ) { throw new UnsupportedOperationException(); } + public void set( int offset, byte[] values, int valOffset, int length ) { throw new UnsupportedOperationException(); } + + public byte replace( int offset, byte val ) { throw new UnsupportedOperationException(); } + + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + + public void reverse() { throw new UnsupportedOperationException(); } + public void reverse( int from, int to ) { throw new UnsupportedOperationException(); } + public void shuffle( Random rand ) { throw new UnsupportedOperationException(); } + + public void sort() { throw new UnsupportedOperationException(); } + public void sort( int fromIndex, int toIndex ) { throw new UnsupportedOperationException(); } + public void fill( byte val ) { throw new UnsupportedOperationException(); } + public void fill( int fromIndex, int toIndex, byte val ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteLongMap.java new file mode 100644 index 0000000..47db4e8 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteLongMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableByteLongMap implements TByteLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteLongMap m; + + public TUnmodifiableByteLongMap( TByteLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( byte key) { return m.get( key ); } + + public long put( byte key, long value ) { throw new UnsupportedOperationException(); } + public long remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient TLongCollection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteLongIterator iterator() { + return new TByteLongIterator() { + TByteLongIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( byte key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( byte key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( byte key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( byte key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteObjectMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteObjectMap.java new file mode 100644 index 0000000..23f3782 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteObjectMap.java @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableByteObjectMap implements TByteObjectMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteObjectMap m; + + public TUnmodifiableByteObjectMap( TByteObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( Object val ) { return m.containsValue( val ); } + public V get( byte key) { return m.get( key ); } + + public V put( byte key, V value ) { throw new UnsupportedOperationException(); } + public V remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteObjectMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient Collection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public Collection valueCollection() { + if ( values == null ) + values = Collections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public Object[] values() { return m.values(); } + public V[] values( V[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TObjectProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteObjectProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteObjectIterator iterator() { + return new TByteObjectIterator() { + TByteObjectIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public V value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public V setValue( V val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public V putIfAbsent( byte key, V value ) { throw new UnsupportedOperationException(); } + public void transformValues( TObjectFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteObjectProcedure procedure ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteSet.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteSet.java new file mode 100644 index 0000000..bc8cbb0 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteSet.java @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import java.io.Serializable; + + +public class TUnmodifiableByteSet extends TUnmodifiableByteCollection + implements TByteSet, Serializable { + + private static final long serialVersionUID = -9215047833775013803L; + + public TUnmodifiableByteSet( TByteSet s ) { super( s ); } + public boolean equals( Object o ) { return o == this || c.equals(o); } + public int hashCode() { return c.hashCode(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteShortMap.java new file mode 100644 index 0000000..dc7fb50 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableByteShortMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableByteShortMap implements TByteShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TByteShortMap m; + + public TUnmodifiableByteShortMap( TByteShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( byte key ) { return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( byte key) { return m.get( key ); } + + public short put( byte key, short value ) { throw new UnsupportedOperationException(); } + public short remove( byte key ) { throw new UnsupportedOperationException(); } + public void putAll( TByteShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TByteSet keySet = null; + private transient TShortCollection values = null; + + public TByteSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public byte[] keys() { return m.keys(); } + public byte[] keys( byte[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TByteProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TByteShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TByteShortIterator iterator() { + return new TByteShortIterator() { + TByteShortIterator iter = m.iterator(); + + public byte key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( byte key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TByteShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( byte key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( byte key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( byte key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharByteMap.java new file mode 100644 index 0000000..cd1c0f3 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharByteMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableCharByteMap implements TCharByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharByteMap m; + + public TUnmodifiableCharByteMap( TCharByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( char key) { return m.get( key ); } + + public byte put( char key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient TByteCollection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharByteIterator iterator() { + return new TCharByteIterator() { + TCharByteIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( char key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( char key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( char key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( char key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharCharMap.java new file mode 100644 index 0000000..59cd6f2 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharCharMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableCharCharMap implements TCharCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharCharMap m; + + public TUnmodifiableCharCharMap( TCharCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( char key) { return m.get( key ); } + + public char put( char key, char value ) { throw new UnsupportedOperationException(); } + public char remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient TCharCollection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharCharIterator iterator() { + return new TCharCharIterator() { + TCharCharIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( char key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( char key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( char key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( char key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharCollection.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharCollection.java new file mode 100644 index 0000000..70f3e8c --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharCollection.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; + + +public class TUnmodifiableCharCollection implements TCharCollection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; + + final TCharCollection c; + + public TUnmodifiableCharCollection( TCharCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + } + + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains( char o ) { return c.contains( o ); } + public char[] toArray() { return c.toArray(); } + public char[] toArray( char[] a ) { return c.toArray( a ); } + public String toString() { return c.toString(); } + public char getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TCharProcedure procedure ) { return c.forEach( procedure ); } + + public TCharIterator iterator() { + return new TCharIterator() { + TCharIterator i = c.iterator(); + + public boolean hasNext() { return i.hasNext(); } + public char next() { return i.next(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public boolean add( char e ) { throw new UnsupportedOperationException(); } + public boolean remove( char o ) { throw new UnsupportedOperationException(); } + + public boolean containsAll( Collection coll ) { return c.containsAll( coll ); } + public boolean containsAll( TCharCollection coll ) { return c.containsAll( coll ); } + public boolean containsAll( char[] array ) { return c.containsAll( array ); } + + public boolean addAll( TCharCollection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( char[] array ) { throw new UnsupportedOperationException(); } + + public boolean removeAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( TCharCollection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( char[] array ) { throw new UnsupportedOperationException(); } + + public boolean retainAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( TCharCollection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( char[] array ) { throw new UnsupportedOperationException(); } + + public void clear() { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharDoubleMap.java new file mode 100644 index 0000000..37b18e7 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharDoubleMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableCharDoubleMap implements TCharDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharDoubleMap m; + + public TUnmodifiableCharDoubleMap( TCharDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( char key) { return m.get( key ); } + + public double put( char key, double value ) { throw new UnsupportedOperationException(); } + public double remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient TDoubleCollection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharDoubleIterator iterator() { + return new TCharDoubleIterator() { + TCharDoubleIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( char key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( char key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( char key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( char key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharFloatMap.java new file mode 100644 index 0000000..f9bf424 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharFloatMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableCharFloatMap implements TCharFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharFloatMap m; + + public TUnmodifiableCharFloatMap( TCharFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( char key) { return m.get( key ); } + + public float put( char key, float value ) { throw new UnsupportedOperationException(); } + public float remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient TFloatCollection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharFloatIterator iterator() { + return new TCharFloatIterator() { + TCharFloatIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( char key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( char key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( char key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( char key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharIntMap.java new file mode 100644 index 0000000..b1ce896 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharIntMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableCharIntMap implements TCharIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharIntMap m; + + public TUnmodifiableCharIntMap( TCharIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( char key) { return m.get( key ); } + + public int put( char key, int value ) { throw new UnsupportedOperationException(); } + public int remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient TIntCollection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharIntIterator iterator() { + return new TCharIntIterator() { + TCharIntIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( char key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( char key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( char key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( char key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharList.java new file mode 100644 index 0000000..026ff3d --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharList.java @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TUnmodifiableCharList extends TUnmodifiableCharCollection implements TCharList { + static final long serialVersionUID = -283967356065247728L; + + final TCharList list; + + public TUnmodifiableCharList( TCharList list ) { + super( list ); + this.list = list; + } + + public boolean equals( Object o ) { return o == this || list.equals( o ); } + public int hashCode() { return list.hashCode(); } + + public char get( int index ) { return list.get( index ); } + public int indexOf( char o ) { return list.indexOf( o ); } + public int lastIndexOf( char o ) { return list.lastIndexOf( o ); } + + public char[] toArray( int offset, int len ) { + return list.toArray( offset, len ); + } + public char[] toArray( char[] dest, int offset, int len ) { + return list.toArray( dest, offset, len ); + } + public char[] toArray( char[] dest, int source_pos, int dest_pos, int len ) { + return list.toArray( dest, source_pos, dest_pos, len ); + } + + public boolean forEachDescending( TCharProcedure procedure ) { + return list.forEachDescending( procedure ); + } + + public int binarySearch( char value ) { return list.binarySearch( value ); } + public int binarySearch( char value, int fromIndex, int toIndex ) { + return list.binarySearch( value, fromIndex, toIndex ); + } + + public int indexOf( int offset, char value ) { return list.indexOf( offset, value ); } + public int lastIndexOf( int offset, char value ) { return list.lastIndexOf( offset, value ); } + public TCharList grep( TCharProcedure condition ) { return list.grep( condition ); } + public TCharList inverseGrep( TCharProcedure condition ) { return list.inverseGrep( condition ); } + + public char max() { return list.max(); } + public char min() { return list.min(); } + public char sum() { return list.sum(); } + + public TCharList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableCharList( list.subList( fromIndex, toIndex ) ); + } + + // TODO: Do we want to fullt implement ListIterator? +// public TIntListIterator listIterator() {return listIterator(0);} +// +// public ListIterator listIterator(final int index) { +// return new ListIterator() { +// ListIterator i = list.listIterator(index); +// +// public boolean hasNext() {return i.hasNext();} +// public E next() {return i.next();} +// public boolean hasPrevious() {return i.hasPrevious();} +// public E previous() {return i.previous();} +// public int nextIndex() {return i.nextIndex();} +// public int previousIndex() {return i.previousIndex();} +// +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// public void set(E e) { +// throw new UnsupportedOperationException(); +// } +// public void add(E e) { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + /** + * UnmodifiableRandomAccessList instances are serialized as + * UnmodifiableList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * UnmodifiableList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, UnmodifiableRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * UnmodifiableList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TUnmodifiableRandomAccessCharList( list ) + : this); + } + + public void add( char[] vals ) { throw new UnsupportedOperationException(); } + public void add( char[] vals, int offset, int length ) { throw new UnsupportedOperationException(); } + + public char removeAt( int offset ) { throw new UnsupportedOperationException(); } + public void remove( int offset, int length ) { throw new UnsupportedOperationException(); } + + public void insert( int offset, char value ) { throw new UnsupportedOperationException(); } + public void insert( int offset, char[] values ) { throw new UnsupportedOperationException(); } + public void insert( int offset, char[] values, int valOffset, int len ) { throw new UnsupportedOperationException(); } + + public char set( int offset, char val ) { throw new UnsupportedOperationException(); } + public void set( int offset, char[] values ) { throw new UnsupportedOperationException(); } + public void set( int offset, char[] values, int valOffset, int length ) { throw new UnsupportedOperationException(); } + + public char replace( int offset, char val ) { throw new UnsupportedOperationException(); } + + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + + public void reverse() { throw new UnsupportedOperationException(); } + public void reverse( int from, int to ) { throw new UnsupportedOperationException(); } + public void shuffle( Random rand ) { throw new UnsupportedOperationException(); } + + public void sort() { throw new UnsupportedOperationException(); } + public void sort( int fromIndex, int toIndex ) { throw new UnsupportedOperationException(); } + public void fill( char val ) { throw new UnsupportedOperationException(); } + public void fill( int fromIndex, int toIndex, char val ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharLongMap.java new file mode 100644 index 0000000..21fe9d1 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharLongMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableCharLongMap implements TCharLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharLongMap m; + + public TUnmodifiableCharLongMap( TCharLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( char key) { return m.get( key ); } + + public long put( char key, long value ) { throw new UnsupportedOperationException(); } + public long remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient TLongCollection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharLongIterator iterator() { + return new TCharLongIterator() { + TCharLongIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( char key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( char key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( char key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( char key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharObjectMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharObjectMap.java new file mode 100644 index 0000000..8faca7d --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharObjectMap.java @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableCharObjectMap implements TCharObjectMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharObjectMap m; + + public TUnmodifiableCharObjectMap( TCharObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( Object val ) { return m.containsValue( val ); } + public V get( char key) { return m.get( key ); } + + public V put( char key, V value ) { throw new UnsupportedOperationException(); } + public V remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharObjectMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient Collection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public Collection valueCollection() { + if ( values == null ) + values = Collections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public Object[] values() { return m.values(); } + public V[] values( V[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TObjectProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharObjectProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharObjectIterator iterator() { + return new TCharObjectIterator() { + TCharObjectIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public V value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public V setValue( V val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public V putIfAbsent( char key, V value ) { throw new UnsupportedOperationException(); } + public void transformValues( TObjectFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharObjectProcedure procedure ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharSet.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharSet.java new file mode 100644 index 0000000..b26fbb2 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharSet.java @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import java.io.Serializable; + + +public class TUnmodifiableCharSet extends TUnmodifiableCharCollection + implements TCharSet, Serializable { + + private static final long serialVersionUID = -9215047833775013803L; + + public TUnmodifiableCharSet( TCharSet s ) { super( s ); } + public boolean equals( Object o ) { return o == this || c.equals(o); } + public int hashCode() { return c.hashCode(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharShortMap.java new file mode 100644 index 0000000..187130c --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableCharShortMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableCharShortMap implements TCharShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TCharShortMap m; + + public TUnmodifiableCharShortMap( TCharShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( char key ) { return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( char key) { return m.get( key ); } + + public short put( char key, short value ) { throw new UnsupportedOperationException(); } + public short remove( char key ) { throw new UnsupportedOperationException(); } + public void putAll( TCharShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TCharSet keySet = null; + private transient TShortCollection values = null; + + public TCharSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public char[] keys() { return m.keys(); } + public char[] keys( char[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TCharProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TCharShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TCharShortIterator iterator() { + return new TCharShortIterator() { + TCharShortIterator iter = m.iterator(); + + public char key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( char key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TCharShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( char key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( char key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( char key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleByteMap.java new file mode 100644 index 0000000..9de9c01 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleByteMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableDoubleByteMap implements TDoubleByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleByteMap m; + + public TUnmodifiableDoubleByteMap( TDoubleByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( double key) { return m.get( key ); } + + public byte put( double key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient TByteCollection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleByteIterator iterator() { + return new TDoubleByteIterator() { + TDoubleByteIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( double key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( double key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( double key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( double key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleCharMap.java new file mode 100644 index 0000000..513a0d1 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleCharMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableDoubleCharMap implements TDoubleCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleCharMap m; + + public TUnmodifiableDoubleCharMap( TDoubleCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( double key) { return m.get( key ); } + + public char put( double key, char value ) { throw new UnsupportedOperationException(); } + public char remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient TCharCollection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleCharIterator iterator() { + return new TDoubleCharIterator() { + TDoubleCharIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( double key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( double key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( double key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( double key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleCollection.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleCollection.java new file mode 100644 index 0000000..a15a5ef --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleCollection.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; + + +public class TUnmodifiableDoubleCollection implements TDoubleCollection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; + + final TDoubleCollection c; + + public TUnmodifiableDoubleCollection( TDoubleCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + } + + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains( double o ) { return c.contains( o ); } + public double[] toArray() { return c.toArray(); } + public double[] toArray( double[] a ) { return c.toArray( a ); } + public String toString() { return c.toString(); } + public double getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TDoubleProcedure procedure ) { return c.forEach( procedure ); } + + public TDoubleIterator iterator() { + return new TDoubleIterator() { + TDoubleIterator i = c.iterator(); + + public boolean hasNext() { return i.hasNext(); } + public double next() { return i.next(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public boolean add( double e ) { throw new UnsupportedOperationException(); } + public boolean remove( double o ) { throw new UnsupportedOperationException(); } + + public boolean containsAll( Collection coll ) { return c.containsAll( coll ); } + public boolean containsAll( TDoubleCollection coll ) { return c.containsAll( coll ); } + public boolean containsAll( double[] array ) { return c.containsAll( array ); } + + public boolean addAll( TDoubleCollection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( double[] array ) { throw new UnsupportedOperationException(); } + + public boolean removeAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( TDoubleCollection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( double[] array ) { throw new UnsupportedOperationException(); } + + public boolean retainAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( TDoubleCollection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( double[] array ) { throw new UnsupportedOperationException(); } + + public void clear() { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleDoubleMap.java new file mode 100644 index 0000000..3ee2bd0 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleDoubleMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableDoubleDoubleMap implements TDoubleDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleDoubleMap m; + + public TUnmodifiableDoubleDoubleMap( TDoubleDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( double key) { return m.get( key ); } + + public double put( double key, double value ) { throw new UnsupportedOperationException(); } + public double remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient TDoubleCollection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleDoubleIterator iterator() { + return new TDoubleDoubleIterator() { + TDoubleDoubleIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( double key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( double key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( double key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( double key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleFloatMap.java new file mode 100644 index 0000000..ed2127b --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleFloatMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableDoubleFloatMap implements TDoubleFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleFloatMap m; + + public TUnmodifiableDoubleFloatMap( TDoubleFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( double key) { return m.get( key ); } + + public float put( double key, float value ) { throw new UnsupportedOperationException(); } + public float remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient TFloatCollection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleFloatIterator iterator() { + return new TDoubleFloatIterator() { + TDoubleFloatIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( double key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( double key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( double key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( double key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleIntMap.java new file mode 100644 index 0000000..3e38a72 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleIntMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableDoubleIntMap implements TDoubleIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleIntMap m; + + public TUnmodifiableDoubleIntMap( TDoubleIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( double key) { return m.get( key ); } + + public int put( double key, int value ) { throw new UnsupportedOperationException(); } + public int remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient TIntCollection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleIntIterator iterator() { + return new TDoubleIntIterator() { + TDoubleIntIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( double key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( double key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( double key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( double key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleList.java new file mode 100644 index 0000000..05737d5 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleList.java @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TUnmodifiableDoubleList extends TUnmodifiableDoubleCollection implements TDoubleList { + static final long serialVersionUID = -283967356065247728L; + + final TDoubleList list; + + public TUnmodifiableDoubleList( TDoubleList list ) { + super( list ); + this.list = list; + } + + public boolean equals( Object o ) { return o == this || list.equals( o ); } + public int hashCode() { return list.hashCode(); } + + public double get( int index ) { return list.get( index ); } + public int indexOf( double o ) { return list.indexOf( o ); } + public int lastIndexOf( double o ) { return list.lastIndexOf( o ); } + + public double[] toArray( int offset, int len ) { + return list.toArray( offset, len ); + } + public double[] toArray( double[] dest, int offset, int len ) { + return list.toArray( dest, offset, len ); + } + public double[] toArray( double[] dest, int source_pos, int dest_pos, int len ) { + return list.toArray( dest, source_pos, dest_pos, len ); + } + + public boolean forEachDescending( TDoubleProcedure procedure ) { + return list.forEachDescending( procedure ); + } + + public int binarySearch( double value ) { return list.binarySearch( value ); } + public int binarySearch( double value, int fromIndex, int toIndex ) { + return list.binarySearch( value, fromIndex, toIndex ); + } + + public int indexOf( int offset, double value ) { return list.indexOf( offset, value ); } + public int lastIndexOf( int offset, double value ) { return list.lastIndexOf( offset, value ); } + public TDoubleList grep( TDoubleProcedure condition ) { return list.grep( condition ); } + public TDoubleList inverseGrep( TDoubleProcedure condition ) { return list.inverseGrep( condition ); } + + public double max() { return list.max(); } + public double min() { return list.min(); } + public double sum() { return list.sum(); } + + public TDoubleList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableDoubleList( list.subList( fromIndex, toIndex ) ); + } + + // TODO: Do we want to fullt implement ListIterator? +// public TIntListIterator listIterator() {return listIterator(0);} +// +// public ListIterator listIterator(final int index) { +// return new ListIterator() { +// ListIterator i = list.listIterator(index); +// +// public boolean hasNext() {return i.hasNext();} +// public E next() {return i.next();} +// public boolean hasPrevious() {return i.hasPrevious();} +// public E previous() {return i.previous();} +// public int nextIndex() {return i.nextIndex();} +// public int previousIndex() {return i.previousIndex();} +// +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// public void set(E e) { +// throw new UnsupportedOperationException(); +// } +// public void add(E e) { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + /** + * UnmodifiableRandomAccessList instances are serialized as + * UnmodifiableList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * UnmodifiableList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, UnmodifiableRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * UnmodifiableList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TUnmodifiableRandomAccessDoubleList( list ) + : this); + } + + public void add( double[] vals ) { throw new UnsupportedOperationException(); } + public void add( double[] vals, int offset, int length ) { throw new UnsupportedOperationException(); } + + public double removeAt( int offset ) { throw new UnsupportedOperationException(); } + public void remove( int offset, int length ) { throw new UnsupportedOperationException(); } + + public void insert( int offset, double value ) { throw new UnsupportedOperationException(); } + public void insert( int offset, double[] values ) { throw new UnsupportedOperationException(); } + public void insert( int offset, double[] values, int valOffset, int len ) { throw new UnsupportedOperationException(); } + + public double set( int offset, double val ) { throw new UnsupportedOperationException(); } + public void set( int offset, double[] values ) { throw new UnsupportedOperationException(); } + public void set( int offset, double[] values, int valOffset, int length ) { throw new UnsupportedOperationException(); } + + public double replace( int offset, double val ) { throw new UnsupportedOperationException(); } + + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + + public void reverse() { throw new UnsupportedOperationException(); } + public void reverse( int from, int to ) { throw new UnsupportedOperationException(); } + public void shuffle( Random rand ) { throw new UnsupportedOperationException(); } + + public void sort() { throw new UnsupportedOperationException(); } + public void sort( int fromIndex, int toIndex ) { throw new UnsupportedOperationException(); } + public void fill( double val ) { throw new UnsupportedOperationException(); } + public void fill( int fromIndex, int toIndex, double val ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleLongMap.java new file mode 100644 index 0000000..c40576f --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleLongMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableDoubleLongMap implements TDoubleLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleLongMap m; + + public TUnmodifiableDoubleLongMap( TDoubleLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( double key) { return m.get( key ); } + + public long put( double key, long value ) { throw new UnsupportedOperationException(); } + public long remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient TLongCollection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleLongIterator iterator() { + return new TDoubleLongIterator() { + TDoubleLongIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( double key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( double key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( double key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( double key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleObjectMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleObjectMap.java new file mode 100644 index 0000000..ba03895 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleObjectMap.java @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableDoubleObjectMap implements TDoubleObjectMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleObjectMap m; + + public TUnmodifiableDoubleObjectMap( TDoubleObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( Object val ) { return m.containsValue( val ); } + public V get( double key) { return m.get( key ); } + + public V put( double key, V value ) { throw new UnsupportedOperationException(); } + public V remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleObjectMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient Collection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public Collection valueCollection() { + if ( values == null ) + values = Collections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public Object[] values() { return m.values(); } + public V[] values( V[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TObjectProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleObjectProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleObjectIterator iterator() { + return new TDoubleObjectIterator() { + TDoubleObjectIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public V value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public V setValue( V val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public V putIfAbsent( double key, V value ) { throw new UnsupportedOperationException(); } + public void transformValues( TObjectFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleObjectProcedure procedure ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleSet.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleSet.java new file mode 100644 index 0000000..08058f1 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleSet.java @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import java.io.Serializable; + + +public class TUnmodifiableDoubleSet extends TUnmodifiableDoubleCollection + implements TDoubleSet, Serializable { + + private static final long serialVersionUID = -9215047833775013803L; + + public TUnmodifiableDoubleSet( TDoubleSet s ) { super( s ); } + public boolean equals( Object o ) { return o == this || c.equals(o); } + public int hashCode() { return c.hashCode(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleShortMap.java new file mode 100644 index 0000000..9674629 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableDoubleShortMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableDoubleShortMap implements TDoubleShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TDoubleShortMap m; + + public TUnmodifiableDoubleShortMap( TDoubleShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( double key ) { return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( double key) { return m.get( key ); } + + public short put( double key, short value ) { throw new UnsupportedOperationException(); } + public short remove( double key ) { throw new UnsupportedOperationException(); } + public void putAll( TDoubleShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TDoubleSet keySet = null; + private transient TShortCollection values = null; + + public TDoubleSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public double[] keys() { return m.keys(); } + public double[] keys( double[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TDoubleProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TDoubleShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TDoubleShortIterator iterator() { + return new TDoubleShortIterator() { + TDoubleShortIterator iter = m.iterator(); + + public double key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( double key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TDoubleShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( double key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( double key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( double key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatByteMap.java new file mode 100644 index 0000000..dcd6e0d --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatByteMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableFloatByteMap implements TFloatByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatByteMap m; + + public TUnmodifiableFloatByteMap( TFloatByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( float key) { return m.get( key ); } + + public byte put( float key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient TByteCollection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatByteIterator iterator() { + return new TFloatByteIterator() { + TFloatByteIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( float key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( float key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( float key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( float key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatCharMap.java new file mode 100644 index 0000000..0182001 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatCharMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableFloatCharMap implements TFloatCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatCharMap m; + + public TUnmodifiableFloatCharMap( TFloatCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( float key) { return m.get( key ); } + + public char put( float key, char value ) { throw new UnsupportedOperationException(); } + public char remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient TCharCollection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatCharIterator iterator() { + return new TFloatCharIterator() { + TFloatCharIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( float key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( float key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( float key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( float key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatCollection.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatCollection.java new file mode 100644 index 0000000..d31f33f --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatCollection.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; + + +public class TUnmodifiableFloatCollection implements TFloatCollection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; + + final TFloatCollection c; + + public TUnmodifiableFloatCollection( TFloatCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + } + + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains( float o ) { return c.contains( o ); } + public float[] toArray() { return c.toArray(); } + public float[] toArray( float[] a ) { return c.toArray( a ); } + public String toString() { return c.toString(); } + public float getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TFloatProcedure procedure ) { return c.forEach( procedure ); } + + public TFloatIterator iterator() { + return new TFloatIterator() { + TFloatIterator i = c.iterator(); + + public boolean hasNext() { return i.hasNext(); } + public float next() { return i.next(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public boolean add( float e ) { throw new UnsupportedOperationException(); } + public boolean remove( float o ) { throw new UnsupportedOperationException(); } + + public boolean containsAll( Collection coll ) { return c.containsAll( coll ); } + public boolean containsAll( TFloatCollection coll ) { return c.containsAll( coll ); } + public boolean containsAll( float[] array ) { return c.containsAll( array ); } + + public boolean addAll( TFloatCollection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( float[] array ) { throw new UnsupportedOperationException(); } + + public boolean removeAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( TFloatCollection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( float[] array ) { throw new UnsupportedOperationException(); } + + public boolean retainAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( TFloatCollection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( float[] array ) { throw new UnsupportedOperationException(); } + + public void clear() { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatDoubleMap.java new file mode 100644 index 0000000..47b0b72 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatDoubleMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableFloatDoubleMap implements TFloatDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatDoubleMap m; + + public TUnmodifiableFloatDoubleMap( TFloatDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( float key) { return m.get( key ); } + + public double put( float key, double value ) { throw new UnsupportedOperationException(); } + public double remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient TDoubleCollection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatDoubleIterator iterator() { + return new TFloatDoubleIterator() { + TFloatDoubleIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( float key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( float key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( float key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( float key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatFloatMap.java new file mode 100644 index 0000000..4c5d555 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatFloatMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableFloatFloatMap implements TFloatFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatFloatMap m; + + public TUnmodifiableFloatFloatMap( TFloatFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( float key) { return m.get( key ); } + + public float put( float key, float value ) { throw new UnsupportedOperationException(); } + public float remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient TFloatCollection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatFloatIterator iterator() { + return new TFloatFloatIterator() { + TFloatFloatIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( float key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( float key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( float key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( float key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatIntMap.java new file mode 100644 index 0000000..91f310c --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatIntMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableFloatIntMap implements TFloatIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatIntMap m; + + public TUnmodifiableFloatIntMap( TFloatIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( float key) { return m.get( key ); } + + public int put( float key, int value ) { throw new UnsupportedOperationException(); } + public int remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient TIntCollection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatIntIterator iterator() { + return new TFloatIntIterator() { + TFloatIntIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( float key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( float key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( float key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( float key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatList.java new file mode 100644 index 0000000..0289fbf --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatList.java @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TUnmodifiableFloatList extends TUnmodifiableFloatCollection implements TFloatList { + static final long serialVersionUID = -283967356065247728L; + + final TFloatList list; + + public TUnmodifiableFloatList( TFloatList list ) { + super( list ); + this.list = list; + } + + public boolean equals( Object o ) { return o == this || list.equals( o ); } + public int hashCode() { return list.hashCode(); } + + public float get( int index ) { return list.get( index ); } + public int indexOf( float o ) { return list.indexOf( o ); } + public int lastIndexOf( float o ) { return list.lastIndexOf( o ); } + + public float[] toArray( int offset, int len ) { + return list.toArray( offset, len ); + } + public float[] toArray( float[] dest, int offset, int len ) { + return list.toArray( dest, offset, len ); + } + public float[] toArray( float[] dest, int source_pos, int dest_pos, int len ) { + return list.toArray( dest, source_pos, dest_pos, len ); + } + + public boolean forEachDescending( TFloatProcedure procedure ) { + return list.forEachDescending( procedure ); + } + + public int binarySearch( float value ) { return list.binarySearch( value ); } + public int binarySearch( float value, int fromIndex, int toIndex ) { + return list.binarySearch( value, fromIndex, toIndex ); + } + + public int indexOf( int offset, float value ) { return list.indexOf( offset, value ); } + public int lastIndexOf( int offset, float value ) { return list.lastIndexOf( offset, value ); } + public TFloatList grep( TFloatProcedure condition ) { return list.grep( condition ); } + public TFloatList inverseGrep( TFloatProcedure condition ) { return list.inverseGrep( condition ); } + + public float max() { return list.max(); } + public float min() { return list.min(); } + public float sum() { return list.sum(); } + + public TFloatList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableFloatList( list.subList( fromIndex, toIndex ) ); + } + + // TODO: Do we want to fullt implement ListIterator? +// public TIntListIterator listIterator() {return listIterator(0);} +// +// public ListIterator listIterator(final int index) { +// return new ListIterator() { +// ListIterator i = list.listIterator(index); +// +// public boolean hasNext() {return i.hasNext();} +// public E next() {return i.next();} +// public boolean hasPrevious() {return i.hasPrevious();} +// public E previous() {return i.previous();} +// public int nextIndex() {return i.nextIndex();} +// public int previousIndex() {return i.previousIndex();} +// +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// public void set(E e) { +// throw new UnsupportedOperationException(); +// } +// public void add(E e) { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + /** + * UnmodifiableRandomAccessList instances are serialized as + * UnmodifiableList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * UnmodifiableList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, UnmodifiableRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * UnmodifiableList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TUnmodifiableRandomAccessFloatList( list ) + : this); + } + + public void add( float[] vals ) { throw new UnsupportedOperationException(); } + public void add( float[] vals, int offset, int length ) { throw new UnsupportedOperationException(); } + + public float removeAt( int offset ) { throw new UnsupportedOperationException(); } + public void remove( int offset, int length ) { throw new UnsupportedOperationException(); } + + public void insert( int offset, float value ) { throw new UnsupportedOperationException(); } + public void insert( int offset, float[] values ) { throw new UnsupportedOperationException(); } + public void insert( int offset, float[] values, int valOffset, int len ) { throw new UnsupportedOperationException(); } + + public float set( int offset, float val ) { throw new UnsupportedOperationException(); } + public void set( int offset, float[] values ) { throw new UnsupportedOperationException(); } + public void set( int offset, float[] values, int valOffset, int length ) { throw new UnsupportedOperationException(); } + + public float replace( int offset, float val ) { throw new UnsupportedOperationException(); } + + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + + public void reverse() { throw new UnsupportedOperationException(); } + public void reverse( int from, int to ) { throw new UnsupportedOperationException(); } + public void shuffle( Random rand ) { throw new UnsupportedOperationException(); } + + public void sort() { throw new UnsupportedOperationException(); } + public void sort( int fromIndex, int toIndex ) { throw new UnsupportedOperationException(); } + public void fill( float val ) { throw new UnsupportedOperationException(); } + public void fill( int fromIndex, int toIndex, float val ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatLongMap.java new file mode 100644 index 0000000..5a13728 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatLongMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableFloatLongMap implements TFloatLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatLongMap m; + + public TUnmodifiableFloatLongMap( TFloatLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( float key) { return m.get( key ); } + + public long put( float key, long value ) { throw new UnsupportedOperationException(); } + public long remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient TLongCollection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatLongIterator iterator() { + return new TFloatLongIterator() { + TFloatLongIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( float key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( float key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( float key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( float key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatObjectMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatObjectMap.java new file mode 100644 index 0000000..eea69e5 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatObjectMap.java @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableFloatObjectMap implements TFloatObjectMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatObjectMap m; + + public TUnmodifiableFloatObjectMap( TFloatObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( Object val ) { return m.containsValue( val ); } + public V get( float key) { return m.get( key ); } + + public V put( float key, V value ) { throw new UnsupportedOperationException(); } + public V remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatObjectMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient Collection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public Collection valueCollection() { + if ( values == null ) + values = Collections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public Object[] values() { return m.values(); } + public V[] values( V[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TObjectProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatObjectProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatObjectIterator iterator() { + return new TFloatObjectIterator() { + TFloatObjectIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public V value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public V setValue( V val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public V putIfAbsent( float key, V value ) { throw new UnsupportedOperationException(); } + public void transformValues( TObjectFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatObjectProcedure procedure ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatSet.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatSet.java new file mode 100644 index 0000000..08ca615 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatSet.java @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import java.io.Serializable; + + +public class TUnmodifiableFloatSet extends TUnmodifiableFloatCollection + implements TFloatSet, Serializable { + + private static final long serialVersionUID = -9215047833775013803L; + + public TUnmodifiableFloatSet( TFloatSet s ) { super( s ); } + public boolean equals( Object o ) { return o == this || c.equals(o); } + public int hashCode() { return c.hashCode(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatShortMap.java new file mode 100644 index 0000000..e864616 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableFloatShortMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableFloatShortMap implements TFloatShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TFloatShortMap m; + + public TUnmodifiableFloatShortMap( TFloatShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( float key ) { return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( float key) { return m.get( key ); } + + public short put( float key, short value ) { throw new UnsupportedOperationException(); } + public short remove( float key ) { throw new UnsupportedOperationException(); } + public void putAll( TFloatShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TFloatSet keySet = null; + private transient TShortCollection values = null; + + public TFloatSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public float[] keys() { return m.keys(); } + public float[] keys( float[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TFloatProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TFloatShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TFloatShortIterator iterator() { + return new TFloatShortIterator() { + TFloatShortIterator iter = m.iterator(); + + public float key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( float key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TFloatShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( float key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( float key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( float key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntByteMap.java new file mode 100644 index 0000000..9aaa39a --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntByteMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableIntByteMap implements TIntByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntByteMap m; + + public TUnmodifiableIntByteMap( TIntByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( int key) { return m.get( key ); } + + public byte put( int key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient TByteCollection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntByteIterator iterator() { + return new TIntByteIterator() { + TIntByteIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( int key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( int key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( int key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( int key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntCharMap.java new file mode 100644 index 0000000..16288c9 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntCharMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableIntCharMap implements TIntCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntCharMap m; + + public TUnmodifiableIntCharMap( TIntCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( int key) { return m.get( key ); } + + public char put( int key, char value ) { throw new UnsupportedOperationException(); } + public char remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient TCharCollection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntCharIterator iterator() { + return new TIntCharIterator() { + TIntCharIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( int key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( int key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( int key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( int key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntCollection.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntCollection.java new file mode 100644 index 0000000..063a94f --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntCollection.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; + + +public class TUnmodifiableIntCollection implements TIntCollection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; + + final TIntCollection c; + + public TUnmodifiableIntCollection( TIntCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + } + + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains( int o ) { return c.contains( o ); } + public int[] toArray() { return c.toArray(); } + public int[] toArray( int[] a ) { return c.toArray( a ); } + public String toString() { return c.toString(); } + public int getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TIntProcedure procedure ) { return c.forEach( procedure ); } + + public TIntIterator iterator() { + return new TIntIterator() { + TIntIterator i = c.iterator(); + + public boolean hasNext() { return i.hasNext(); } + public int next() { return i.next(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public boolean add( int e ) { throw new UnsupportedOperationException(); } + public boolean remove( int o ) { throw new UnsupportedOperationException(); } + + public boolean containsAll( Collection coll ) { return c.containsAll( coll ); } + public boolean containsAll( TIntCollection coll ) { return c.containsAll( coll ); } + public boolean containsAll( int[] array ) { return c.containsAll( array ); } + + public boolean addAll( TIntCollection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( int[] array ) { throw new UnsupportedOperationException(); } + + public boolean removeAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( TIntCollection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( int[] array ) { throw new UnsupportedOperationException(); } + + public boolean retainAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( TIntCollection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( int[] array ) { throw new UnsupportedOperationException(); } + + public void clear() { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntDoubleMap.java new file mode 100644 index 0000000..d5d4616 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntDoubleMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableIntDoubleMap implements TIntDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntDoubleMap m; + + public TUnmodifiableIntDoubleMap( TIntDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( int key) { return m.get( key ); } + + public double put( int key, double value ) { throw new UnsupportedOperationException(); } + public double remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient TDoubleCollection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntDoubleIterator iterator() { + return new TIntDoubleIterator() { + TIntDoubleIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( int key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( int key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( int key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( int key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntFloatMap.java new file mode 100644 index 0000000..f3af6ba --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntFloatMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableIntFloatMap implements TIntFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntFloatMap m; + + public TUnmodifiableIntFloatMap( TIntFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( int key) { return m.get( key ); } + + public float put( int key, float value ) { throw new UnsupportedOperationException(); } + public float remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient TFloatCollection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntFloatIterator iterator() { + return new TIntFloatIterator() { + TIntFloatIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( int key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( int key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( int key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( int key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntIntMap.java new file mode 100644 index 0000000..284da69 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntIntMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableIntIntMap implements TIntIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntIntMap m; + + public TUnmodifiableIntIntMap( TIntIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( int key) { return m.get( key ); } + + public int put( int key, int value ) { throw new UnsupportedOperationException(); } + public int remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient TIntCollection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntIntIterator iterator() { + return new TIntIntIterator() { + TIntIntIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( int key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( int key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( int key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( int key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntList.java new file mode 100644 index 0000000..1e5eaa9 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntList.java @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TUnmodifiableIntList extends TUnmodifiableIntCollection implements TIntList { + static final long serialVersionUID = -283967356065247728L; + + final TIntList list; + + public TUnmodifiableIntList( TIntList list ) { + super( list ); + this.list = list; + } + + public boolean equals( Object o ) { return o == this || list.equals( o ); } + public int hashCode() { return list.hashCode(); } + + public int get( int index ) { return list.get( index ); } + public int indexOf( int o ) { return list.indexOf( o ); } + public int lastIndexOf( int o ) { return list.lastIndexOf( o ); } + + public int[] toArray( int offset, int len ) { + return list.toArray( offset, len ); + } + public int[] toArray( int[] dest, int offset, int len ) { + return list.toArray( dest, offset, len ); + } + public int[] toArray( int[] dest, int source_pos, int dest_pos, int len ) { + return list.toArray( dest, source_pos, dest_pos, len ); + } + + public boolean forEachDescending( TIntProcedure procedure ) { + return list.forEachDescending( procedure ); + } + + public int binarySearch( int value ) { return list.binarySearch( value ); } + public int binarySearch( int value, int fromIndex, int toIndex ) { + return list.binarySearch( value, fromIndex, toIndex ); + } + + public int indexOf( int offset, int value ) { return list.indexOf( offset, value ); } + public int lastIndexOf( int offset, int value ) { return list.lastIndexOf( offset, value ); } + public TIntList grep( TIntProcedure condition ) { return list.grep( condition ); } + public TIntList inverseGrep( TIntProcedure condition ) { return list.inverseGrep( condition ); } + + public int max() { return list.max(); } + public int min() { return list.min(); } + public int sum() { return list.sum(); } + + public TIntList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableIntList( list.subList( fromIndex, toIndex ) ); + } + + // TODO: Do we want to fullt implement ListIterator? +// public TIntListIterator listIterator() {return listIterator(0);} +// +// public ListIterator listIterator(final int index) { +// return new ListIterator() { +// ListIterator i = list.listIterator(index); +// +// public boolean hasNext() {return i.hasNext();} +// public E next() {return i.next();} +// public boolean hasPrevious() {return i.hasPrevious();} +// public E previous() {return i.previous();} +// public int nextIndex() {return i.nextIndex();} +// public int previousIndex() {return i.previousIndex();} +// +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// public void set(E e) { +// throw new UnsupportedOperationException(); +// } +// public void add(E e) { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + /** + * UnmodifiableRandomAccessList instances are serialized as + * UnmodifiableList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * UnmodifiableList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, UnmodifiableRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * UnmodifiableList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TUnmodifiableRandomAccessIntList( list ) + : this); + } + + public void add( int[] vals ) { throw new UnsupportedOperationException(); } + public void add( int[] vals, int offset, int length ) { throw new UnsupportedOperationException(); } + + public int removeAt( int offset ) { throw new UnsupportedOperationException(); } + public void remove( int offset, int length ) { throw new UnsupportedOperationException(); } + + public void insert( int offset, int value ) { throw new UnsupportedOperationException(); } + public void insert( int offset, int[] values ) { throw new UnsupportedOperationException(); } + public void insert( int offset, int[] values, int valOffset, int len ) { throw new UnsupportedOperationException(); } + + public int set( int offset, int val ) { throw new UnsupportedOperationException(); } + public void set( int offset, int[] values ) { throw new UnsupportedOperationException(); } + public void set( int offset, int[] values, int valOffset, int length ) { throw new UnsupportedOperationException(); } + + public int replace( int offset, int val ) { throw new UnsupportedOperationException(); } + + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + + public void reverse() { throw new UnsupportedOperationException(); } + public void reverse( int from, int to ) { throw new UnsupportedOperationException(); } + public void shuffle( Random rand ) { throw new UnsupportedOperationException(); } + + public void sort() { throw new UnsupportedOperationException(); } + public void sort( int fromIndex, int toIndex ) { throw new UnsupportedOperationException(); } + public void fill( int val ) { throw new UnsupportedOperationException(); } + public void fill( int fromIndex, int toIndex, int val ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntLongMap.java new file mode 100644 index 0000000..b75e854 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntLongMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableIntLongMap implements TIntLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntLongMap m; + + public TUnmodifiableIntLongMap( TIntLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( int key) { return m.get( key ); } + + public long put( int key, long value ) { throw new UnsupportedOperationException(); } + public long remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient TLongCollection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntLongIterator iterator() { + return new TIntLongIterator() { + TIntLongIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( int key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( int key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( int key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( int key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntObjectMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntObjectMap.java new file mode 100644 index 0000000..d97e4cb --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntObjectMap.java @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableIntObjectMap implements TIntObjectMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntObjectMap m; + + public TUnmodifiableIntObjectMap( TIntObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( Object val ) { return m.containsValue( val ); } + public V get( int key) { return m.get( key ); } + + public V put( int key, V value ) { throw new UnsupportedOperationException(); } + public V remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntObjectMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient Collection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public Collection valueCollection() { + if ( values == null ) + values = Collections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public Object[] values() { return m.values(); } + public V[] values( V[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TObjectProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntObjectProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntObjectIterator iterator() { + return new TIntObjectIterator() { + TIntObjectIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public V value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public V setValue( V val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public V putIfAbsent( int key, V value ) { throw new UnsupportedOperationException(); } + public void transformValues( TObjectFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntObjectProcedure procedure ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntSet.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntSet.java new file mode 100644 index 0000000..3b32a4b --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntSet.java @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import java.io.Serializable; + + +public class TUnmodifiableIntSet extends TUnmodifiableIntCollection + implements TIntSet, Serializable { + + private static final long serialVersionUID = -9215047833775013803L; + + public TUnmodifiableIntSet( TIntSet s ) { super( s ); } + public boolean equals( Object o ) { return o == this || c.equals(o); } + public int hashCode() { return c.hashCode(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntShortMap.java new file mode 100644 index 0000000..6138569 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableIntShortMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableIntShortMap implements TIntShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TIntShortMap m; + + public TUnmodifiableIntShortMap( TIntShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( int key ) { return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( int key) { return m.get( key ); } + + public short put( int key, short value ) { throw new UnsupportedOperationException(); } + public short remove( int key ) { throw new UnsupportedOperationException(); } + public void putAll( TIntShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TIntSet keySet = null; + private transient TShortCollection values = null; + + public TIntSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public int[] keys() { return m.keys(); } + public int[] keys( int[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TIntProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TIntShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TIntShortIterator iterator() { + return new TIntShortIterator() { + TIntShortIterator iter = m.iterator(); + + public int key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( int key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TIntShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( int key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( int key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( int key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongByteMap.java new file mode 100644 index 0000000..b3c7592 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongByteMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableLongByteMap implements TLongByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongByteMap m; + + public TUnmodifiableLongByteMap( TLongByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( long key) { return m.get( key ); } + + public byte put( long key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient TByteCollection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongByteIterator iterator() { + return new TLongByteIterator() { + TLongByteIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( long key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( long key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( long key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( long key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongCharMap.java new file mode 100644 index 0000000..96ea41f --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongCharMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableLongCharMap implements TLongCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongCharMap m; + + public TUnmodifiableLongCharMap( TLongCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( long key) { return m.get( key ); } + + public char put( long key, char value ) { throw new UnsupportedOperationException(); } + public char remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient TCharCollection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongCharIterator iterator() { + return new TLongCharIterator() { + TLongCharIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( long key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( long key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( long key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( long key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongCollection.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongCollection.java new file mode 100644 index 0000000..4be0d46 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongCollection.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; + + +public class TUnmodifiableLongCollection implements TLongCollection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; + + final TLongCollection c; + + public TUnmodifiableLongCollection( TLongCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + } + + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains( long o ) { return c.contains( o ); } + public long[] toArray() { return c.toArray(); } + public long[] toArray( long[] a ) { return c.toArray( a ); } + public String toString() { return c.toString(); } + public long getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TLongProcedure procedure ) { return c.forEach( procedure ); } + + public TLongIterator iterator() { + return new TLongIterator() { + TLongIterator i = c.iterator(); + + public boolean hasNext() { return i.hasNext(); } + public long next() { return i.next(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public boolean add( long e ) { throw new UnsupportedOperationException(); } + public boolean remove( long o ) { throw new UnsupportedOperationException(); } + + public boolean containsAll( Collection coll ) { return c.containsAll( coll ); } + public boolean containsAll( TLongCollection coll ) { return c.containsAll( coll ); } + public boolean containsAll( long[] array ) { return c.containsAll( array ); } + + public boolean addAll( TLongCollection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( long[] array ) { throw new UnsupportedOperationException(); } + + public boolean removeAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( TLongCollection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( long[] array ) { throw new UnsupportedOperationException(); } + + public boolean retainAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( TLongCollection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( long[] array ) { throw new UnsupportedOperationException(); } + + public void clear() { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongDoubleMap.java new file mode 100644 index 0000000..294eefb --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongDoubleMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableLongDoubleMap implements TLongDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongDoubleMap m; + + public TUnmodifiableLongDoubleMap( TLongDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( long key) { return m.get( key ); } + + public double put( long key, double value ) { throw new UnsupportedOperationException(); } + public double remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient TDoubleCollection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongDoubleIterator iterator() { + return new TLongDoubleIterator() { + TLongDoubleIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( long key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( long key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( long key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( long key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongFloatMap.java new file mode 100644 index 0000000..a21d1ae --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongFloatMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableLongFloatMap implements TLongFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongFloatMap m; + + public TUnmodifiableLongFloatMap( TLongFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( long key) { return m.get( key ); } + + public float put( long key, float value ) { throw new UnsupportedOperationException(); } + public float remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient TFloatCollection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongFloatIterator iterator() { + return new TLongFloatIterator() { + TLongFloatIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( long key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( long key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( long key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( long key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongIntMap.java new file mode 100644 index 0000000..81169ea --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongIntMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableLongIntMap implements TLongIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongIntMap m; + + public TUnmodifiableLongIntMap( TLongIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( long key) { return m.get( key ); } + + public int put( long key, int value ) { throw new UnsupportedOperationException(); } + public int remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient TIntCollection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongIntIterator iterator() { + return new TLongIntIterator() { + TLongIntIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( long key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( long key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( long key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( long key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongList.java new file mode 100644 index 0000000..e5a7f25 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongList.java @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TUnmodifiableLongList extends TUnmodifiableLongCollection implements TLongList { + static final long serialVersionUID = -283967356065247728L; + + final TLongList list; + + public TUnmodifiableLongList( TLongList list ) { + super( list ); + this.list = list; + } + + public boolean equals( Object o ) { return o == this || list.equals( o ); } + public int hashCode() { return list.hashCode(); } + + public long get( int index ) { return list.get( index ); } + public int indexOf( long o ) { return list.indexOf( o ); } + public int lastIndexOf( long o ) { return list.lastIndexOf( o ); } + + public long[] toArray( int offset, int len ) { + return list.toArray( offset, len ); + } + public long[] toArray( long[] dest, int offset, int len ) { + return list.toArray( dest, offset, len ); + } + public long[] toArray( long[] dest, int source_pos, int dest_pos, int len ) { + return list.toArray( dest, source_pos, dest_pos, len ); + } + + public boolean forEachDescending( TLongProcedure procedure ) { + return list.forEachDescending( procedure ); + } + + public int binarySearch( long value ) { return list.binarySearch( value ); } + public int binarySearch( long value, int fromIndex, int toIndex ) { + return list.binarySearch( value, fromIndex, toIndex ); + } + + public int indexOf( int offset, long value ) { return list.indexOf( offset, value ); } + public int lastIndexOf( int offset, long value ) { return list.lastIndexOf( offset, value ); } + public TLongList grep( TLongProcedure condition ) { return list.grep( condition ); } + public TLongList inverseGrep( TLongProcedure condition ) { return list.inverseGrep( condition ); } + + public long max() { return list.max(); } + public long min() { return list.min(); } + public long sum() { return list.sum(); } + + public TLongList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableLongList( list.subList( fromIndex, toIndex ) ); + } + + // TODO: Do we want to fullt implement ListIterator? +// public TIntListIterator listIterator() {return listIterator(0);} +// +// public ListIterator listIterator(final int index) { +// return new ListIterator() { +// ListIterator i = list.listIterator(index); +// +// public boolean hasNext() {return i.hasNext();} +// public E next() {return i.next();} +// public boolean hasPrevious() {return i.hasPrevious();} +// public E previous() {return i.previous();} +// public int nextIndex() {return i.nextIndex();} +// public int previousIndex() {return i.previousIndex();} +// +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// public void set(E e) { +// throw new UnsupportedOperationException(); +// } +// public void add(E e) { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + /** + * UnmodifiableRandomAccessList instances are serialized as + * UnmodifiableList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * UnmodifiableList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, UnmodifiableRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * UnmodifiableList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TUnmodifiableRandomAccessLongList( list ) + : this); + } + + public void add( long[] vals ) { throw new UnsupportedOperationException(); } + public void add( long[] vals, int offset, int length ) { throw new UnsupportedOperationException(); } + + public long removeAt( int offset ) { throw new UnsupportedOperationException(); } + public void remove( int offset, int length ) { throw new UnsupportedOperationException(); } + + public void insert( int offset, long value ) { throw new UnsupportedOperationException(); } + public void insert( int offset, long[] values ) { throw new UnsupportedOperationException(); } + public void insert( int offset, long[] values, int valOffset, int len ) { throw new UnsupportedOperationException(); } + + public long set( int offset, long val ) { throw new UnsupportedOperationException(); } + public void set( int offset, long[] values ) { throw new UnsupportedOperationException(); } + public void set( int offset, long[] values, int valOffset, int length ) { throw new UnsupportedOperationException(); } + + public long replace( int offset, long val ) { throw new UnsupportedOperationException(); } + + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + + public void reverse() { throw new UnsupportedOperationException(); } + public void reverse( int from, int to ) { throw new UnsupportedOperationException(); } + public void shuffle( Random rand ) { throw new UnsupportedOperationException(); } + + public void sort() { throw new UnsupportedOperationException(); } + public void sort( int fromIndex, int toIndex ) { throw new UnsupportedOperationException(); } + public void fill( long val ) { throw new UnsupportedOperationException(); } + public void fill( int fromIndex, int toIndex, long val ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongLongMap.java new file mode 100644 index 0000000..030250f --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongLongMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableLongLongMap implements TLongLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongLongMap m; + + public TUnmodifiableLongLongMap( TLongLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( long key) { return m.get( key ); } + + public long put( long key, long value ) { throw new UnsupportedOperationException(); } + public long remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient TLongCollection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongLongIterator iterator() { + return new TLongLongIterator() { + TLongLongIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( long key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( long key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( long key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( long key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongObjectMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongObjectMap.java new file mode 100644 index 0000000..ef59cb2 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongObjectMap.java @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableLongObjectMap implements TLongObjectMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongObjectMap m; + + public TUnmodifiableLongObjectMap( TLongObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( Object val ) { return m.containsValue( val ); } + public V get( long key) { return m.get( key ); } + + public V put( long key, V value ) { throw new UnsupportedOperationException(); } + public V remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongObjectMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient Collection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public Collection valueCollection() { + if ( values == null ) + values = Collections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public Object[] values() { return m.values(); } + public V[] values( V[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TObjectProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongObjectProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongObjectIterator iterator() { + return new TLongObjectIterator() { + TLongObjectIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public V value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public V setValue( V val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public V putIfAbsent( long key, V value ) { throw new UnsupportedOperationException(); } + public void transformValues( TObjectFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongObjectProcedure procedure ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongSet.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongSet.java new file mode 100644 index 0000000..a3afe36 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongSet.java @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import java.io.Serializable; + + +public class TUnmodifiableLongSet extends TUnmodifiableLongCollection + implements TLongSet, Serializable { + + private static final long serialVersionUID = -9215047833775013803L; + + public TUnmodifiableLongSet( TLongSet s ) { super( s ); } + public boolean equals( Object o ) { return o == this || c.equals(o); } + public int hashCode() { return c.hashCode(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongShortMap.java new file mode 100644 index 0000000..a5b319a --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableLongShortMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableLongShortMap implements TLongShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TLongShortMap m; + + public TUnmodifiableLongShortMap( TLongShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( long key ) { return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( long key) { return m.get( key ); } + + public short put( long key, short value ) { throw new UnsupportedOperationException(); } + public short remove( long key ) { throw new UnsupportedOperationException(); } + public void putAll( TLongShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TLongSet keySet = null; + private transient TShortCollection values = null; + + public TLongSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public long[] keys() { return m.keys(); } + public long[] keys( long[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TLongProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TLongShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TLongShortIterator iterator() { + return new TLongShortIterator() { + TLongShortIterator iter = m.iterator(); + + public long key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( long key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TLongShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( long key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( long key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( long key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectByteMap.java new file mode 100644 index 0000000..c3a41de --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectByteMap.java @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableObjectByteMap implements TObjectByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TObjectByteMap m; + + public TUnmodifiableObjectByteMap( TObjectByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( Object key ){ return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( Object key ) { return m.get( key ); } + + public byte put( K key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( Object key ) { throw new UnsupportedOperationException(); } + public void putAll( TObjectByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient Set keySet = null; + private transient TByteCollection values = null; + + public Set keySet() { + if ( keySet == null ) + keySet = Collections.unmodifiableSet( m.keySet() ); + return keySet; + } + public Object[] keys() { return m.keys(); } + public K[] keys( K[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TObjectProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TObjectByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TObjectByteIterator iterator() { + return new TObjectByteIterator() { + TObjectByteIterator iter = m.iterator(); + + public K key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( K key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TObjectByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( K key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( K key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( K key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectCharMap.java new file mode 100644 index 0000000..19a647a --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectCharMap.java @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableObjectCharMap implements TObjectCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TObjectCharMap m; + + public TUnmodifiableObjectCharMap( TObjectCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( Object key ){ return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( Object key ) { return m.get( key ); } + + public char put( K key, char value ) { throw new UnsupportedOperationException(); } + public char remove( Object key ) { throw new UnsupportedOperationException(); } + public void putAll( TObjectCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient Set keySet = null; + private transient TCharCollection values = null; + + public Set keySet() { + if ( keySet == null ) + keySet = Collections.unmodifiableSet( m.keySet() ); + return keySet; + } + public Object[] keys() { return m.keys(); } + public K[] keys( K[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TObjectProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TObjectCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TObjectCharIterator iterator() { + return new TObjectCharIterator() { + TObjectCharIterator iter = m.iterator(); + + public K key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( K key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TObjectCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( K key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( K key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( K key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectDoubleMap.java new file mode 100644 index 0000000..ee26c18 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectDoubleMap.java @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableObjectDoubleMap implements TObjectDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TObjectDoubleMap m; + + public TUnmodifiableObjectDoubleMap( TObjectDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( Object key ){ return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( Object key ) { return m.get( key ); } + + public double put( K key, double value ) { throw new UnsupportedOperationException(); } + public double remove( Object key ) { throw new UnsupportedOperationException(); } + public void putAll( TObjectDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient Set keySet = null; + private transient TDoubleCollection values = null; + + public Set keySet() { + if ( keySet == null ) + keySet = Collections.unmodifiableSet( m.keySet() ); + return keySet; + } + public Object[] keys() { return m.keys(); } + public K[] keys( K[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TObjectProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TObjectDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TObjectDoubleIterator iterator() { + return new TObjectDoubleIterator() { + TObjectDoubleIterator iter = m.iterator(); + + public K key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( K key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TObjectDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( K key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( K key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( K key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectFloatMap.java new file mode 100644 index 0000000..a314984 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectFloatMap.java @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableObjectFloatMap implements TObjectFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TObjectFloatMap m; + + public TUnmodifiableObjectFloatMap( TObjectFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( Object key ){ return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( Object key ) { return m.get( key ); } + + public float put( K key, float value ) { throw new UnsupportedOperationException(); } + public float remove( Object key ) { throw new UnsupportedOperationException(); } + public void putAll( TObjectFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient Set keySet = null; + private transient TFloatCollection values = null; + + public Set keySet() { + if ( keySet == null ) + keySet = Collections.unmodifiableSet( m.keySet() ); + return keySet; + } + public Object[] keys() { return m.keys(); } + public K[] keys( K[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TObjectProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TObjectFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TObjectFloatIterator iterator() { + return new TObjectFloatIterator() { + TObjectFloatIterator iter = m.iterator(); + + public K key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( K key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TObjectFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( K key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( K key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( K key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectIntMap.java new file mode 100644 index 0000000..3d915fb --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectIntMap.java @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableObjectIntMap implements TObjectIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TObjectIntMap m; + + public TUnmodifiableObjectIntMap( TObjectIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( Object key ){ return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( Object key ) { return m.get( key ); } + + public int put( K key, int value ) { throw new UnsupportedOperationException(); } + public int remove( Object key ) { throw new UnsupportedOperationException(); } + public void putAll( TObjectIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient Set keySet = null; + private transient TIntCollection values = null; + + public Set keySet() { + if ( keySet == null ) + keySet = Collections.unmodifiableSet( m.keySet() ); + return keySet; + } + public Object[] keys() { return m.keys(); } + public K[] keys( K[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TObjectProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TObjectIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TObjectIntIterator iterator() { + return new TObjectIntIterator() { + TObjectIntIterator iter = m.iterator(); + + public K key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( K key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TObjectIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( K key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( K key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( K key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectLongMap.java new file mode 100644 index 0000000..059c7f5 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectLongMap.java @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableObjectLongMap implements TObjectLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TObjectLongMap m; + + public TUnmodifiableObjectLongMap( TObjectLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( Object key ){ return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( Object key ) { return m.get( key ); } + + public long put( K key, long value ) { throw new UnsupportedOperationException(); } + public long remove( Object key ) { throw new UnsupportedOperationException(); } + public void putAll( TObjectLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient Set keySet = null; + private transient TLongCollection values = null; + + public Set keySet() { + if ( keySet == null ) + keySet = Collections.unmodifiableSet( m.keySet() ); + return keySet; + } + public Object[] keys() { return m.keys(); } + public K[] keys( K[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TObjectProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TObjectLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TObjectLongIterator iterator() { + return new TObjectLongIterator() { + TObjectLongIterator iter = m.iterator(); + + public K key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( K key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TObjectLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( K key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( K key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( K key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectShortMap.java new file mode 100644 index 0000000..8f851fc --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableObjectShortMap.java @@ -0,0 +1,119 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableObjectShortMap implements TObjectShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TObjectShortMap m; + + public TUnmodifiableObjectShortMap( TObjectShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( Object key ){ return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( Object key ) { return m.get( key ); } + + public short put( K key, short value ) { throw new UnsupportedOperationException(); } + public short remove( Object key ) { throw new UnsupportedOperationException(); } + public void putAll( TObjectShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient Set keySet = null; + private transient TShortCollection values = null; + + public Set keySet() { + if ( keySet == null ) + keySet = Collections.unmodifiableSet( m.keySet() ); + return keySet; + } + public Object[] keys() { return m.keys(); } + public K[] keys( K[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TObjectProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TObjectShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TObjectShortIterator iterator() { + return new TObjectShortIterator() { + TObjectShortIterator iter = m.iterator(); + + public K key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( K key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TObjectShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( K key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( K key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( K key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessByteList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessByteList.java new file mode 100644 index 0000000..3b607f5 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessByteList.java @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TUnmodifiableRandomAccessByteList extends TUnmodifiableByteList + implements RandomAccess { + + private static final long serialVersionUID = -2542308836966382001L; + + public TUnmodifiableRandomAccessByteList( TByteList list ) { + super( list ); + } + + public TByteList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableRandomAccessByteList( list.subList( fromIndex, toIndex ) ); + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have UnmodifiableRandomAccessList). UnmodifiableList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TUnmodifiableByteList( list ); + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessCharList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessCharList.java new file mode 100644 index 0000000..a2a6e0b --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessCharList.java @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TUnmodifiableRandomAccessCharList extends TUnmodifiableCharList + implements RandomAccess { + + private static final long serialVersionUID = -2542308836966382001L; + + public TUnmodifiableRandomAccessCharList( TCharList list ) { + super( list ); + } + + public TCharList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableRandomAccessCharList( list.subList( fromIndex, toIndex ) ); + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have UnmodifiableRandomAccessList). UnmodifiableList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TUnmodifiableCharList( list ); + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessDoubleList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessDoubleList.java new file mode 100644 index 0000000..7018188 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessDoubleList.java @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TUnmodifiableRandomAccessDoubleList extends TUnmodifiableDoubleList + implements RandomAccess { + + private static final long serialVersionUID = -2542308836966382001L; + + public TUnmodifiableRandomAccessDoubleList( TDoubleList list ) { + super( list ); + } + + public TDoubleList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableRandomAccessDoubleList( list.subList( fromIndex, toIndex ) ); + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have UnmodifiableRandomAccessList). UnmodifiableList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TUnmodifiableDoubleList( list ); + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessFloatList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessFloatList.java new file mode 100644 index 0000000..0b4489e --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessFloatList.java @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TUnmodifiableRandomAccessFloatList extends TUnmodifiableFloatList + implements RandomAccess { + + private static final long serialVersionUID = -2542308836966382001L; + + public TUnmodifiableRandomAccessFloatList( TFloatList list ) { + super( list ); + } + + public TFloatList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableRandomAccessFloatList( list.subList( fromIndex, toIndex ) ); + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have UnmodifiableRandomAccessList). UnmodifiableList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TUnmodifiableFloatList( list ); + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessIntList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessIntList.java new file mode 100644 index 0000000..5275a95 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessIntList.java @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TUnmodifiableRandomAccessIntList extends TUnmodifiableIntList + implements RandomAccess { + + private static final long serialVersionUID = -2542308836966382001L; + + public TUnmodifiableRandomAccessIntList( TIntList list ) { + super( list ); + } + + public TIntList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableRandomAccessIntList( list.subList( fromIndex, toIndex ) ); + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have UnmodifiableRandomAccessList). UnmodifiableList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TUnmodifiableIntList( list ); + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessLongList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessLongList.java new file mode 100644 index 0000000..83f788e --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessLongList.java @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TUnmodifiableRandomAccessLongList extends TUnmodifiableLongList + implements RandomAccess { + + private static final long serialVersionUID = -2542308836966382001L; + + public TUnmodifiableRandomAccessLongList( TLongList list ) { + super( list ); + } + + public TLongList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableRandomAccessLongList( list.subList( fromIndex, toIndex ) ); + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have UnmodifiableRandomAccessList). UnmodifiableList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TUnmodifiableLongList( list ); + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessShortList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessShortList.java new file mode 100644 index 0000000..c91ce4c --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableRandomAccessShortList.java @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.list.*; +import java.util.RandomAccess; + + +public class TUnmodifiableRandomAccessShortList extends TUnmodifiableShortList + implements RandomAccess { + + private static final long serialVersionUID = -2542308836966382001L; + + public TUnmodifiableRandomAccessShortList( TShortList list ) { + super( list ); + } + + public TShortList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableRandomAccessShortList( list.subList( fromIndex, toIndex ) ); + } + + /** + * Allows instances to be deserialized in pre-1.4 JREs (which do + * not have UnmodifiableRandomAccessList). UnmodifiableList has + * a readResolve method that inverts this transformation upon + * deserialization. + */ + private Object writeReplace() { + return new TUnmodifiableShortList( list ); + } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortByteMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortByteMap.java new file mode 100644 index 0000000..1c88ee7 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortByteMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableShortByteMap implements TShortByteMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortByteMap m; + + public TUnmodifiableShortByteMap( TShortByteMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( byte val ) { return m.containsValue( val ); } + public byte get( short key) { return m.get( key ); } + + public byte put( short key, byte value ) { throw new UnsupportedOperationException(); } + public byte remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortByteMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient TByteCollection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public TByteCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public byte[] values() { return m.values(); } + public byte[] values( byte[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + public byte getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TByteProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortByteProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortByteIterator iterator() { + return new TShortByteIterator() { + TShortByteIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public byte value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public byte setValue( byte val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public byte putIfAbsent( short key, byte value ) { throw new UnsupportedOperationException(); } + public void transformValues( TByteFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortByteProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( short key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( short key, byte amount ) { throw new UnsupportedOperationException(); } + public byte adjustOrPutValue( short key, byte adjust_amount, byte put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortCharMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortCharMap.java new file mode 100644 index 0000000..67dd3c0 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortCharMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableShortCharMap implements TShortCharMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortCharMap m; + + public TUnmodifiableShortCharMap( TShortCharMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( char val ) { return m.containsValue( val ); } + public char get( short key) { return m.get( key ); } + + public char put( short key, char value ) { throw new UnsupportedOperationException(); } + public char remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortCharMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient TCharCollection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public TCharCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public char[] values() { return m.values(); } + public char[] values( char[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + public char getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TCharProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortCharProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortCharIterator iterator() { + return new TShortCharIterator() { + TShortCharIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public char value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public char setValue( char val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public char putIfAbsent( short key, char value ) { throw new UnsupportedOperationException(); } + public void transformValues( TCharFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortCharProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( short key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( short key, char amount ) { throw new UnsupportedOperationException(); } + public char adjustOrPutValue( short key, char adjust_amount, char put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortCollection.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortCollection.java new file mode 100644 index 0000000..1ada1ee --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortCollection.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.*; + +import java.util.Collection; +import java.io.Serializable; + + +public class TUnmodifiableShortCollection implements TShortCollection, Serializable { + private static final long serialVersionUID = 1820017752578914078L; + + final TShortCollection c; + + public TUnmodifiableShortCollection( TShortCollection c ) { + if ( c == null ) + throw new NullPointerException(); + this.c = c; + } + + public int size() { return c.size(); } + public boolean isEmpty() { return c.isEmpty(); } + public boolean contains( short o ) { return c.contains( o ); } + public short[] toArray() { return c.toArray(); } + public short[] toArray( short[] a ) { return c.toArray( a ); } + public String toString() { return c.toString(); } + public short getNoEntryValue() { return c.getNoEntryValue(); } + public boolean forEach( TShortProcedure procedure ) { return c.forEach( procedure ); } + + public TShortIterator iterator() { + return new TShortIterator() { + TShortIterator i = c.iterator(); + + public boolean hasNext() { return i.hasNext(); } + public short next() { return i.next(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public boolean add( short e ) { throw new UnsupportedOperationException(); } + public boolean remove( short o ) { throw new UnsupportedOperationException(); } + + public boolean containsAll( Collection coll ) { return c.containsAll( coll ); } + public boolean containsAll( TShortCollection coll ) { return c.containsAll( coll ); } + public boolean containsAll( short[] array ) { return c.containsAll( array ); } + + public boolean addAll( TShortCollection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean addAll( short[] array ) { throw new UnsupportedOperationException(); } + + public boolean removeAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( TShortCollection coll ) { throw new UnsupportedOperationException(); } + public boolean removeAll( short[] array ) { throw new UnsupportedOperationException(); } + + public boolean retainAll( Collection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( TShortCollection coll ) { throw new UnsupportedOperationException(); } + public boolean retainAll( short[] array ) { throw new UnsupportedOperationException(); } + + public void clear() { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortDoubleMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortDoubleMap.java new file mode 100644 index 0000000..ac554f9 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortDoubleMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableShortDoubleMap implements TShortDoubleMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortDoubleMap m; + + public TUnmodifiableShortDoubleMap( TShortDoubleMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( double val ) { return m.containsValue( val ); } + public double get( short key) { return m.get( key ); } + + public double put( short key, double value ) { throw new UnsupportedOperationException(); } + public double remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortDoubleMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient TDoubleCollection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public TDoubleCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public double[] values() { return m.values(); } + public double[] values( double[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + public double getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TDoubleProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortDoubleProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortDoubleIterator iterator() { + return new TShortDoubleIterator() { + TShortDoubleIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public double value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public double setValue( double val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public double putIfAbsent( short key, double value ) { throw new UnsupportedOperationException(); } + public void transformValues( TDoubleFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortDoubleProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( short key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( short key, double amount ) { throw new UnsupportedOperationException(); } + public double adjustOrPutValue( short key, double adjust_amount, double put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortFloatMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortFloatMap.java new file mode 100644 index 0000000..85871ce --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortFloatMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableShortFloatMap implements TShortFloatMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortFloatMap m; + + public TUnmodifiableShortFloatMap( TShortFloatMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( float val ) { return m.containsValue( val ); } + public float get( short key) { return m.get( key ); } + + public float put( short key, float value ) { throw new UnsupportedOperationException(); } + public float remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortFloatMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient TFloatCollection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public TFloatCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public float[] values() { return m.values(); } + public float[] values( float[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + public float getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TFloatProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortFloatProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortFloatIterator iterator() { + return new TShortFloatIterator() { + TShortFloatIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public float value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public float setValue( float val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public float putIfAbsent( short key, float value ) { throw new UnsupportedOperationException(); } + public void transformValues( TFloatFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortFloatProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( short key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( short key, float amount ) { throw new UnsupportedOperationException(); } + public float adjustOrPutValue( short key, float adjust_amount, float put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortIntMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortIntMap.java new file mode 100644 index 0000000..459613e --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortIntMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableShortIntMap implements TShortIntMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortIntMap m; + + public TUnmodifiableShortIntMap( TShortIntMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( int val ) { return m.containsValue( val ); } + public int get( short key) { return m.get( key ); } + + public int put( short key, int value ) { throw new UnsupportedOperationException(); } + public int remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortIntMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient TIntCollection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public TIntCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public int[] values() { return m.values(); } + public int[] values( int[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + public int getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TIntProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortIntProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortIntIterator iterator() { + return new TShortIntIterator() { + TShortIntIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public int value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public int setValue( int val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public int putIfAbsent( short key, int value ) { throw new UnsupportedOperationException(); } + public void transformValues( TIntFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortIntProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( short key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( short key, int amount ) { throw new UnsupportedOperationException(); } + public int adjustOrPutValue( short key, int adjust_amount, int put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortList.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortList.java new file mode 100644 index 0000000..7510ba5 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortList.java @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.procedure.*; +import gnu.trove.list.*; +import gnu.trove.function.*; +import java.util.RandomAccess; +import java.util.Random; + + +public class TUnmodifiableShortList extends TUnmodifiableShortCollection implements TShortList { + static final long serialVersionUID = -283967356065247728L; + + final TShortList list; + + public TUnmodifiableShortList( TShortList list ) { + super( list ); + this.list = list; + } + + public boolean equals( Object o ) { return o == this || list.equals( o ); } + public int hashCode() { return list.hashCode(); } + + public short get( int index ) { return list.get( index ); } + public int indexOf( short o ) { return list.indexOf( o ); } + public int lastIndexOf( short o ) { return list.lastIndexOf( o ); } + + public short[] toArray( int offset, int len ) { + return list.toArray( offset, len ); + } + public short[] toArray( short[] dest, int offset, int len ) { + return list.toArray( dest, offset, len ); + } + public short[] toArray( short[] dest, int source_pos, int dest_pos, int len ) { + return list.toArray( dest, source_pos, dest_pos, len ); + } + + public boolean forEachDescending( TShortProcedure procedure ) { + return list.forEachDescending( procedure ); + } + + public int binarySearch( short value ) { return list.binarySearch( value ); } + public int binarySearch( short value, int fromIndex, int toIndex ) { + return list.binarySearch( value, fromIndex, toIndex ); + } + + public int indexOf( int offset, short value ) { return list.indexOf( offset, value ); } + public int lastIndexOf( int offset, short value ) { return list.lastIndexOf( offset, value ); } + public TShortList grep( TShortProcedure condition ) { return list.grep( condition ); } + public TShortList inverseGrep( TShortProcedure condition ) { return list.inverseGrep( condition ); } + + public short max() { return list.max(); } + public short min() { return list.min(); } + public short sum() { return list.sum(); } + + public TShortList subList( int fromIndex, int toIndex ) { + return new TUnmodifiableShortList( list.subList( fromIndex, toIndex ) ); + } + + // TODO: Do we want to fullt implement ListIterator? +// public TIntListIterator listIterator() {return listIterator(0);} +// +// public ListIterator listIterator(final int index) { +// return new ListIterator() { +// ListIterator i = list.listIterator(index); +// +// public boolean hasNext() {return i.hasNext();} +// public E next() {return i.next();} +// public boolean hasPrevious() {return i.hasPrevious();} +// public E previous() {return i.previous();} +// public int nextIndex() {return i.nextIndex();} +// public int previousIndex() {return i.previousIndex();} +// +// public void remove() { +// throw new UnsupportedOperationException(); +// } +// public void set(E e) { +// throw new UnsupportedOperationException(); +// } +// public void add(E e) { +// throw new UnsupportedOperationException(); +// } +// }; +// } + + /** + * UnmodifiableRandomAccessList instances are serialized as + * UnmodifiableList instances to allow them to be deserialized + * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList). + * This method inverts the transformation. As a beneficial + * side-effect, it also grafts the RandomAccess marker onto + * UnmodifiableList instances that were serialized in pre-1.4 JREs. + * + * Note: Unfortunately, UnmodifiableRandomAccessList instances + * serialized in 1.4.1 and deserialized in 1.4 will become + * UnmodifiableList instances, as this method was missing in 1.4. + */ + private Object readResolve() { + return ( list instanceof RandomAccess + ? new TUnmodifiableRandomAccessShortList( list ) + : this); + } + + public void add( short[] vals ) { throw new UnsupportedOperationException(); } + public void add( short[] vals, int offset, int length ) { throw new UnsupportedOperationException(); } + + public short removeAt( int offset ) { throw new UnsupportedOperationException(); } + public void remove( int offset, int length ) { throw new UnsupportedOperationException(); } + + public void insert( int offset, short value ) { throw new UnsupportedOperationException(); } + public void insert( int offset, short[] values ) { throw new UnsupportedOperationException(); } + public void insert( int offset, short[] values, int valOffset, int len ) { throw new UnsupportedOperationException(); } + + public short set( int offset, short val ) { throw new UnsupportedOperationException(); } + public void set( int offset, short[] values ) { throw new UnsupportedOperationException(); } + public void set( int offset, short[] values, int valOffset, int length ) { throw new UnsupportedOperationException(); } + + public short replace( int offset, short val ) { throw new UnsupportedOperationException(); } + + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + + public void reverse() { throw new UnsupportedOperationException(); } + public void reverse( int from, int to ) { throw new UnsupportedOperationException(); } + public void shuffle( Random rand ) { throw new UnsupportedOperationException(); } + + public void sort() { throw new UnsupportedOperationException(); } + public void sort( int fromIndex, int toIndex ) { throw new UnsupportedOperationException(); } + public void fill( short val ) { throw new UnsupportedOperationException(); } + public void fill( int fromIndex, int toIndex, short val ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortLongMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortLongMap.java new file mode 100644 index 0000000..9c0abad --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortLongMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableShortLongMap implements TShortLongMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortLongMap m; + + public TUnmodifiableShortLongMap( TShortLongMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( long val ) { return m.containsValue( val ); } + public long get( short key) { return m.get( key ); } + + public long put( short key, long value ) { throw new UnsupportedOperationException(); } + public long remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortLongMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient TLongCollection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public TLongCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public long[] values() { return m.values(); } + public long[] values( long[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + public long getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TLongProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortLongProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortLongIterator iterator() { + return new TShortLongIterator() { + TShortLongIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public long value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public long setValue( long val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public long putIfAbsent( short key, long value ) { throw new UnsupportedOperationException(); } + public void transformValues( TLongFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortLongProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( short key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( short key, long amount ) { throw new UnsupportedOperationException(); } + public long adjustOrPutValue( short key, long adjust_amount, long put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortObjectMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortObjectMap.java new file mode 100644 index 0000000..cf26c6a --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortObjectMap.java @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.*; +import java.io.Serializable; + + +public class TUnmodifiableShortObjectMap implements TShortObjectMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortObjectMap m; + + public TUnmodifiableShortObjectMap( TShortObjectMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( Object val ) { return m.containsValue( val ); } + public V get( short key) { return m.get( key ); } + + public V put( short key, V value ) { throw new UnsupportedOperationException(); } + public V remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortObjectMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient Collection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public Collection valueCollection() { + if ( values == null ) + values = Collections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public Object[] values() { return m.values(); } + public V[] values( V[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TObjectProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortObjectProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortObjectIterator iterator() { + return new TShortObjectIterator() { + TShortObjectIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public V value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public V setValue( V val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public V putIfAbsent( short key, V value ) { throw new UnsupportedOperationException(); } + public void transformValues( TObjectFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortObjectProcedure procedure ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortSet.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortSet.java new file mode 100644 index 0000000..71c5438 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortSet.java @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.set.*; +import java.io.Serializable; + + +public class TUnmodifiableShortSet extends TUnmodifiableShortCollection + implements TShortSet, Serializable { + + private static final long serialVersionUID = -9215047833775013803L; + + public TUnmodifiableShortSet( TShortSet s ) { super( s ); } + public boolean equals( Object o ) { return o == this || c.equals(o); } + public int hashCode() { return c.hashCode(); } +} diff --git a/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortShortMap.java b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortShortMap.java new file mode 100644 index 0000000..c4c5f37 --- /dev/null +++ b/src/gnu/trove/impl/unmodifiable/TUnmodifiableShortShortMap.java @@ -0,0 +1,121 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2008, Robert D. Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.impl.unmodifiable; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// THIS IS AN IMPLEMENTATION CLASS. DO NOT USE DIRECTLY! // +// Access to these methods should be through TCollections // +//////////////////////////////////////////////////////////// + + +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.function.*; +import gnu.trove.map.*; +import gnu.trove.*; + +import java.util.Map; +import java.io.Serializable; + + +public class TUnmodifiableShortShortMap implements TShortShortMap, Serializable { + private static final long serialVersionUID = -1034234728574286014L; + + private final TShortShortMap m; + + public TUnmodifiableShortShortMap( TShortShortMap m ) { + if ( m == null ) + throw new NullPointerException(); + this.m = m; + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean containsKey( short key ) { return m.containsKey( key ); } + public boolean containsValue( short val ) { return m.containsValue( val ); } + public short get( short key) { return m.get( key ); } + + public short put( short key, short value ) { throw new UnsupportedOperationException(); } + public short remove( short key ) { throw new UnsupportedOperationException(); } + public void putAll( TShortShortMap m ) { throw new UnsupportedOperationException(); } + public void putAll( Map map ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + + private transient TShortSet keySet = null; + private transient TShortCollection values = null; + + public TShortSet keySet() { + if ( keySet == null ) + keySet = TCollections.unmodifiableSet( m.keySet() ); + return keySet; + } + public short[] keys() { return m.keys(); } + public short[] keys( short[] array ) { return m.keys( array ); } + + public TShortCollection valueCollection() { + if ( values == null ) + values = TCollections.unmodifiableCollection( m.valueCollection() ); + return values; + } + public short[] values() { return m.values(); } + public short[] values( short[] array ) { return m.values( array ); } + + public boolean equals(Object o) { return o == this || m.equals(o); } + public int hashCode() { return m.hashCode(); } + public String toString() { return m.toString(); } + public short getNoEntryKey() { return m.getNoEntryKey(); } + public short getNoEntryValue() { return m.getNoEntryValue(); } + + public boolean forEachKey( TShortProcedure procedure ) { + return m.forEachKey( procedure ); + } + public boolean forEachValue( TShortProcedure procedure ) { + return m.forEachValue( procedure ); + } + public boolean forEachEntry( TShortShortProcedure procedure ) { + return m.forEachEntry( procedure ); + } + + public TShortShortIterator iterator() { + return new TShortShortIterator() { + TShortShortIterator iter = m.iterator(); + + public short key() { return iter.key(); } + public short value() { return iter.value(); } + public void advance() { iter.advance(); } + public boolean hasNext() { return iter.hasNext(); } + public short setValue( short val ) { throw new UnsupportedOperationException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + public short putIfAbsent( short key, short value ) { throw new UnsupportedOperationException(); } + public void transformValues( TShortFunction function ) { throw new UnsupportedOperationException(); } + public boolean retainEntries( TShortShortProcedure procedure ) { throw new UnsupportedOperationException(); } + public boolean increment( short key ) { throw new UnsupportedOperationException(); } + public boolean adjustValue( short key, short amount ) { throw new UnsupportedOperationException(); } + public short adjustOrPutValue( short key, short adjust_amount, short put_amount ) { throw new UnsupportedOperationException(); } +} diff --git a/src/gnu/trove/iterator/TAdvancingIterator.java b/src/gnu/trove/iterator/TAdvancingIterator.java new file mode 100644 index 0000000..86db71d --- /dev/null +++ b/src/gnu/trove/iterator/TAdvancingIterator.java @@ -0,0 +1,31 @@ +// //////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// //////////////////////////////////////////////////////////////////////////// +package gnu.trove.iterator; + +/** + * Common interface for iterators that operate via the "advance" method for moving the + * cursor to the next element. + */ +public interface TAdvancingIterator extends TIterator { + /** + * Moves the iterator forward to the next entry. + * + * @throws java.util.NoSuchElementException if the iterator is already exhausted + */ + public void advance(); +} diff --git a/src/gnu/trove/iterator/TByteByteIterator.java b/src/gnu/trove/iterator/TByteByteIterator.java new file mode 100644 index 0000000..3d5d79b --- /dev/null +++ b/src/gnu/trove/iterator/TByteByteIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and byte. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TByteByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TByteByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TByteByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TByteByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TByteByteIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TByteCharIterator.java b/src/gnu/trove/iterator/TByteCharIterator.java new file mode 100644 index 0000000..6f85482 --- /dev/null +++ b/src/gnu/trove/iterator/TByteCharIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and char. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TByteCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TByteCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TByteCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TByteCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TByteCharIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TByteDoubleIterator.java b/src/gnu/trove/iterator/TByteDoubleIterator.java new file mode 100644 index 0000000..bf017b3 --- /dev/null +++ b/src/gnu/trove/iterator/TByteDoubleIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and double. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TByteDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TByteDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TByteDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TByteDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TByteDoubleIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TByteFloatIterator.java b/src/gnu/trove/iterator/TByteFloatIterator.java new file mode 100644 index 0000000..12239cc --- /dev/null +++ b/src/gnu/trove/iterator/TByteFloatIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and float. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TByteFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TByteFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TByteFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TByteFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TByteFloatIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TByteIntIterator.java b/src/gnu/trove/iterator/TByteIntIterator.java new file mode 100644 index 0000000..0b62006 --- /dev/null +++ b/src/gnu/trove/iterator/TByteIntIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and int. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TByteIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TByteIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TByteIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TByteIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TByteIntIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TByteIterator.java b/src/gnu/trove/iterator/TByteIterator.java new file mode 100644 index 0000000..0b04859 --- /dev/null +++ b/src/gnu/trove/iterator/TByteIterator.java @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for byte collections. + */ +public interface TByteIterator extends TIterator { + /** + * Advances the iterator to the next element in the underlying collection + * and returns it. + * + * @return the next byte in the collection + * @exception NoSuchElementException if the iterator is already exhausted + */ + public byte next(); +} diff --git a/src/gnu/trove/iterator/TByteLongIterator.java b/src/gnu/trove/iterator/TByteLongIterator.java new file mode 100644 index 0000000..20866d9 --- /dev/null +++ b/src/gnu/trove/iterator/TByteLongIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and long. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TByteLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TByteLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TByteLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TByteLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TByteLongIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TByteObjectIterator.java b/src/gnu/trove/iterator/TByteObjectIterator.java new file mode 100644 index 0000000..7059785 --- /dev/null +++ b/src/gnu/trove/iterator/TByteObjectIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and Object. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TByteObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TByteObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TByteObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TByteObjectIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $ + */ +public interface TByteObjectIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public V value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public V setValue( V val ); +} diff --git a/src/gnu/trove/iterator/TByteShortIterator.java b/src/gnu/trove/iterator/TByteShortIterator.java new file mode 100644 index 0000000..1dd6c6c --- /dev/null +++ b/src/gnu/trove/iterator/TByteShortIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type byte and short. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TByteShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TByteShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TByteShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TByteShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TByteShortIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public byte key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/TCharByteIterator.java b/src/gnu/trove/iterator/TCharByteIterator.java new file mode 100644 index 0000000..fba280b --- /dev/null +++ b/src/gnu/trove/iterator/TCharByteIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and byte. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TCharByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TCharByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TCharByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TCharByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TCharByteIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TCharCharIterator.java b/src/gnu/trove/iterator/TCharCharIterator.java new file mode 100644 index 0000000..f2dc427 --- /dev/null +++ b/src/gnu/trove/iterator/TCharCharIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and char. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TCharCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TCharCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TCharCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TCharCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TCharCharIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TCharDoubleIterator.java b/src/gnu/trove/iterator/TCharDoubleIterator.java new file mode 100644 index 0000000..caa99fa --- /dev/null +++ b/src/gnu/trove/iterator/TCharDoubleIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and double. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TCharDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TCharDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TCharDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TCharDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TCharDoubleIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TCharFloatIterator.java b/src/gnu/trove/iterator/TCharFloatIterator.java new file mode 100644 index 0000000..05b5527 --- /dev/null +++ b/src/gnu/trove/iterator/TCharFloatIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and float. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TCharFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TCharFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TCharFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TCharFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TCharFloatIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TCharIntIterator.java b/src/gnu/trove/iterator/TCharIntIterator.java new file mode 100644 index 0000000..44dd852 --- /dev/null +++ b/src/gnu/trove/iterator/TCharIntIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and int. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TCharIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TCharIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TCharIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TCharIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TCharIntIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TCharIterator.java b/src/gnu/trove/iterator/TCharIterator.java new file mode 100644 index 0000000..eb0891b --- /dev/null +++ b/src/gnu/trove/iterator/TCharIterator.java @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for char collections. + */ +public interface TCharIterator extends TIterator { + /** + * Advances the iterator to the next element in the underlying collection + * and returns it. + * + * @return the next char in the collection + * @exception NoSuchElementException if the iterator is already exhausted + */ + public char next(); +} diff --git a/src/gnu/trove/iterator/TCharLongIterator.java b/src/gnu/trove/iterator/TCharLongIterator.java new file mode 100644 index 0000000..353de8b --- /dev/null +++ b/src/gnu/trove/iterator/TCharLongIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and long. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TCharLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TCharLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TCharLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TCharLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TCharLongIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TCharObjectIterator.java b/src/gnu/trove/iterator/TCharObjectIterator.java new file mode 100644 index 0000000..fafd555 --- /dev/null +++ b/src/gnu/trove/iterator/TCharObjectIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and Object. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TCharObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TCharObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TCharObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TCharObjectIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $ + */ +public interface TCharObjectIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public V value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public V setValue( V val ); +} diff --git a/src/gnu/trove/iterator/TCharShortIterator.java b/src/gnu/trove/iterator/TCharShortIterator.java new file mode 100644 index 0000000..f851620 --- /dev/null +++ b/src/gnu/trove/iterator/TCharShortIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type char and short. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TCharShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TCharShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TCharShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TCharShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TCharShortIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public char key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/TDoubleByteIterator.java b/src/gnu/trove/iterator/TDoubleByteIterator.java new file mode 100644 index 0000000..a6ffd1e --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleByteIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and byte. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TDoubleByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TDoubleByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TDoubleByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TDoubleByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TDoubleByteIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TDoubleCharIterator.java b/src/gnu/trove/iterator/TDoubleCharIterator.java new file mode 100644 index 0000000..2e34c71 --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleCharIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and char. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TDoubleCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TDoubleCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TDoubleCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TDoubleCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TDoubleCharIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TDoubleDoubleIterator.java b/src/gnu/trove/iterator/TDoubleDoubleIterator.java new file mode 100644 index 0000000..d6ce46c --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleDoubleIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and double. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TDoubleDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TDoubleDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TDoubleDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TDoubleDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TDoubleDoubleIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TDoubleFloatIterator.java b/src/gnu/trove/iterator/TDoubleFloatIterator.java new file mode 100644 index 0000000..74ad1a8 --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleFloatIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and float. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TDoubleFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TDoubleFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TDoubleFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TDoubleFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TDoubleFloatIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TDoubleIntIterator.java b/src/gnu/trove/iterator/TDoubleIntIterator.java new file mode 100644 index 0000000..893f5f3 --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleIntIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and int. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TDoubleIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TDoubleIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TDoubleIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TDoubleIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TDoubleIntIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TDoubleIterator.java b/src/gnu/trove/iterator/TDoubleIterator.java new file mode 100644 index 0000000..9c079f5 --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleIterator.java @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for double collections. + */ +public interface TDoubleIterator extends TIterator { + /** + * Advances the iterator to the next element in the underlying collection + * and returns it. + * + * @return the next double in the collection + * @exception NoSuchElementException if the iterator is already exhausted + */ + public double next(); +} diff --git a/src/gnu/trove/iterator/TDoubleLongIterator.java b/src/gnu/trove/iterator/TDoubleLongIterator.java new file mode 100644 index 0000000..362cfeb --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleLongIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and long. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TDoubleLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TDoubleLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TDoubleLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TDoubleLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TDoubleLongIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TDoubleObjectIterator.java b/src/gnu/trove/iterator/TDoubleObjectIterator.java new file mode 100644 index 0000000..515080f --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleObjectIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and Object. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TDoubleObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TDoubleObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TDoubleObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TDoubleObjectIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $ + */ +public interface TDoubleObjectIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public V value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public V setValue( V val ); +} diff --git a/src/gnu/trove/iterator/TDoubleShortIterator.java b/src/gnu/trove/iterator/TDoubleShortIterator.java new file mode 100644 index 0000000..8089239 --- /dev/null +++ b/src/gnu/trove/iterator/TDoubleShortIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type double and short. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TDoubleShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TDoubleShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TDoubleShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TDoubleShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TDoubleShortIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public double key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/TFloatByteIterator.java b/src/gnu/trove/iterator/TFloatByteIterator.java new file mode 100644 index 0000000..b1cae6c --- /dev/null +++ b/src/gnu/trove/iterator/TFloatByteIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and byte. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TFloatByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TFloatByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TFloatByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TFloatByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TFloatByteIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TFloatCharIterator.java b/src/gnu/trove/iterator/TFloatCharIterator.java new file mode 100644 index 0000000..640cd86 --- /dev/null +++ b/src/gnu/trove/iterator/TFloatCharIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and char. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TFloatCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TFloatCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TFloatCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TFloatCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TFloatCharIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TFloatDoubleIterator.java b/src/gnu/trove/iterator/TFloatDoubleIterator.java new file mode 100644 index 0000000..d0f3631 --- /dev/null +++ b/src/gnu/trove/iterator/TFloatDoubleIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and double. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TFloatDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TFloatDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TFloatDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TFloatDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TFloatDoubleIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TFloatFloatIterator.java b/src/gnu/trove/iterator/TFloatFloatIterator.java new file mode 100644 index 0000000..c4f1351 --- /dev/null +++ b/src/gnu/trove/iterator/TFloatFloatIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and float. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TFloatFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TFloatFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TFloatFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TFloatFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TFloatFloatIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TFloatIntIterator.java b/src/gnu/trove/iterator/TFloatIntIterator.java new file mode 100644 index 0000000..568bfdf --- /dev/null +++ b/src/gnu/trove/iterator/TFloatIntIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and int. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TFloatIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TFloatIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TFloatIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TFloatIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TFloatIntIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TFloatIterator.java b/src/gnu/trove/iterator/TFloatIterator.java new file mode 100644 index 0000000..79acefc --- /dev/null +++ b/src/gnu/trove/iterator/TFloatIterator.java @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for float collections. + */ +public interface TFloatIterator extends TIterator { + /** + * Advances the iterator to the next element in the underlying collection + * and returns it. + * + * @return the next float in the collection + * @exception NoSuchElementException if the iterator is already exhausted + */ + public float next(); +} diff --git a/src/gnu/trove/iterator/TFloatLongIterator.java b/src/gnu/trove/iterator/TFloatLongIterator.java new file mode 100644 index 0000000..cada5cc --- /dev/null +++ b/src/gnu/trove/iterator/TFloatLongIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and long. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TFloatLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TFloatLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TFloatLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TFloatLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TFloatLongIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TFloatObjectIterator.java b/src/gnu/trove/iterator/TFloatObjectIterator.java new file mode 100644 index 0000000..c31483c --- /dev/null +++ b/src/gnu/trove/iterator/TFloatObjectIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and Object. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TFloatObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TFloatObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TFloatObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TFloatObjectIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $ + */ +public interface TFloatObjectIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public V value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public V setValue( V val ); +} diff --git a/src/gnu/trove/iterator/TFloatShortIterator.java b/src/gnu/trove/iterator/TFloatShortIterator.java new file mode 100644 index 0000000..28f401b --- /dev/null +++ b/src/gnu/trove/iterator/TFloatShortIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type float and short. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TFloatShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TFloatShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TFloatShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TFloatShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TFloatShortIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public float key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/TIntByteIterator.java b/src/gnu/trove/iterator/TIntByteIterator.java new file mode 100644 index 0000000..36e6e60 --- /dev/null +++ b/src/gnu/trove/iterator/TIntByteIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and byte. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TIntByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TIntByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TIntByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TIntByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TIntByteIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TIntCharIterator.java b/src/gnu/trove/iterator/TIntCharIterator.java new file mode 100644 index 0000000..08b1664 --- /dev/null +++ b/src/gnu/trove/iterator/TIntCharIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and char. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TIntCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TIntCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TIntCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TIntCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TIntCharIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TIntDoubleIterator.java b/src/gnu/trove/iterator/TIntDoubleIterator.java new file mode 100644 index 0000000..2793f9c --- /dev/null +++ b/src/gnu/trove/iterator/TIntDoubleIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and double. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TIntDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TIntDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TIntDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TIntDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TIntDoubleIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TIntFloatIterator.java b/src/gnu/trove/iterator/TIntFloatIterator.java new file mode 100644 index 0000000..a28e498 --- /dev/null +++ b/src/gnu/trove/iterator/TIntFloatIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and float. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TIntFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TIntFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TIntFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TIntFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TIntFloatIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TIntIntIterator.java b/src/gnu/trove/iterator/TIntIntIterator.java new file mode 100644 index 0000000..531deb3 --- /dev/null +++ b/src/gnu/trove/iterator/TIntIntIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and int. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TIntIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TIntIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TIntIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TIntIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TIntIntIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TIntIterator.java b/src/gnu/trove/iterator/TIntIterator.java new file mode 100644 index 0000000..3e1fdd2 --- /dev/null +++ b/src/gnu/trove/iterator/TIntIterator.java @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for int collections. + */ +public interface TIntIterator extends TIterator { + /** + * Advances the iterator to the next element in the underlying collection + * and returns it. + * + * @return the next int in the collection + * @exception NoSuchElementException if the iterator is already exhausted + */ + public int next(); +} diff --git a/src/gnu/trove/iterator/TIntLongIterator.java b/src/gnu/trove/iterator/TIntLongIterator.java new file mode 100644 index 0000000..7342734 --- /dev/null +++ b/src/gnu/trove/iterator/TIntLongIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and long. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TIntLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TIntLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TIntLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TIntLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TIntLongIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TIntObjectIterator.java b/src/gnu/trove/iterator/TIntObjectIterator.java new file mode 100644 index 0000000..cb41d34 --- /dev/null +++ b/src/gnu/trove/iterator/TIntObjectIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and Object. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TIntObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TIntObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TIntObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TIntObjectIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $ + */ +public interface TIntObjectIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public V value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public V setValue( V val ); +} diff --git a/src/gnu/trove/iterator/TIntShortIterator.java b/src/gnu/trove/iterator/TIntShortIterator.java new file mode 100644 index 0000000..715c5c5 --- /dev/null +++ b/src/gnu/trove/iterator/TIntShortIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type int and short. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TIntShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TIntShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TIntShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TIntShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TIntShortIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public int key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/TIterator.java b/src/gnu/trove/iterator/TIterator.java new file mode 100644 index 0000000..efdf22e --- /dev/null +++ b/src/gnu/trove/iterator/TIterator.java @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// +package gnu.trove.iterator; + +/** + * Common interface for all iterators used in Trove. + */ +public interface TIterator { + /** + * Returns true if the iterator can be advanced past its current location. + * + * @return a boolean value + */ + public boolean hasNext(); + + /** + * Removes the last entry returned by the iterator. The result of invoking this method + * more than once for a single entry is undefined and can leave the underlying data + * structure in a confused state. + */ + public void remove(); +} diff --git a/src/gnu/trove/iterator/TLongByteIterator.java b/src/gnu/trove/iterator/TLongByteIterator.java new file mode 100644 index 0000000..6d51754 --- /dev/null +++ b/src/gnu/trove/iterator/TLongByteIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and byte. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TLongByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TLongByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TLongByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TLongByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TLongByteIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TLongCharIterator.java b/src/gnu/trove/iterator/TLongCharIterator.java new file mode 100644 index 0000000..4365bfe --- /dev/null +++ b/src/gnu/trove/iterator/TLongCharIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and char. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TLongCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TLongCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TLongCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TLongCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TLongCharIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TLongDoubleIterator.java b/src/gnu/trove/iterator/TLongDoubleIterator.java new file mode 100644 index 0000000..2d3487a --- /dev/null +++ b/src/gnu/trove/iterator/TLongDoubleIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and double. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TLongDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TLongDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TLongDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TLongDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TLongDoubleIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TLongFloatIterator.java b/src/gnu/trove/iterator/TLongFloatIterator.java new file mode 100644 index 0000000..84ea53b --- /dev/null +++ b/src/gnu/trove/iterator/TLongFloatIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and float. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TLongFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TLongFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TLongFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TLongFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TLongFloatIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TLongIntIterator.java b/src/gnu/trove/iterator/TLongIntIterator.java new file mode 100644 index 0000000..2b9ef36 --- /dev/null +++ b/src/gnu/trove/iterator/TLongIntIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and int. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TLongIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TLongIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TLongIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TLongIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TLongIntIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TLongIterator.java b/src/gnu/trove/iterator/TLongIterator.java new file mode 100644 index 0000000..2798501 --- /dev/null +++ b/src/gnu/trove/iterator/TLongIterator.java @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for long collections. + */ +public interface TLongIterator extends TIterator { + /** + * Advances the iterator to the next element in the underlying collection + * and returns it. + * + * @return the next long in the collection + * @exception NoSuchElementException if the iterator is already exhausted + */ + public long next(); +} diff --git a/src/gnu/trove/iterator/TLongLongIterator.java b/src/gnu/trove/iterator/TLongLongIterator.java new file mode 100644 index 0000000..f1bd16a --- /dev/null +++ b/src/gnu/trove/iterator/TLongLongIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and long. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TLongLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TLongLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TLongLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TLongLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TLongLongIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TLongObjectIterator.java b/src/gnu/trove/iterator/TLongObjectIterator.java new file mode 100644 index 0000000..82bb2cd --- /dev/null +++ b/src/gnu/trove/iterator/TLongObjectIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and Object. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TLongObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TLongObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TLongObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TLongObjectIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $ + */ +public interface TLongObjectIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public V value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public V setValue( V val ); +} diff --git a/src/gnu/trove/iterator/TLongShortIterator.java b/src/gnu/trove/iterator/TLongShortIterator.java new file mode 100644 index 0000000..545f146 --- /dev/null +++ b/src/gnu/trove/iterator/TLongShortIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type long and short. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TLongShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TLongShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TLongShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TLongShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TLongShortIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public long key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/TObjectByteIterator.java b/src/gnu/trove/iterator/TObjectByteIterator.java new file mode 100644 index 0000000..4dfc690 --- /dev/null +++ b/src/gnu/trove/iterator/TObjectByteIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type Object and byte. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TObjectByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TObjectByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TObjectByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TObjectByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: Object_E_Iterator.template,v 1.1.2.1 2009/09/14 19:02:20 upholderoftruth Exp $ + */ +public interface TObjectByteIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public K key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TObjectCharIterator.java b/src/gnu/trove/iterator/TObjectCharIterator.java new file mode 100644 index 0000000..8b7352a --- /dev/null +++ b/src/gnu/trove/iterator/TObjectCharIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type Object and char. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TObjectCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TObjectCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TObjectCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TObjectCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: Object_E_Iterator.template,v 1.1.2.1 2009/09/14 19:02:20 upholderoftruth Exp $ + */ +public interface TObjectCharIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public K key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TObjectDoubleIterator.java b/src/gnu/trove/iterator/TObjectDoubleIterator.java new file mode 100644 index 0000000..ccc43f1 --- /dev/null +++ b/src/gnu/trove/iterator/TObjectDoubleIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type Object and double. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TObjectDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TObjectDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TObjectDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TObjectDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: Object_E_Iterator.template,v 1.1.2.1 2009/09/14 19:02:20 upholderoftruth Exp $ + */ +public interface TObjectDoubleIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public K key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TObjectFloatIterator.java b/src/gnu/trove/iterator/TObjectFloatIterator.java new file mode 100644 index 0000000..8de6c34 --- /dev/null +++ b/src/gnu/trove/iterator/TObjectFloatIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type Object and float. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TObjectFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TObjectFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TObjectFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TObjectFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: Object_E_Iterator.template,v 1.1.2.1 2009/09/14 19:02:20 upholderoftruth Exp $ + */ +public interface TObjectFloatIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public K key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TObjectIntIterator.java b/src/gnu/trove/iterator/TObjectIntIterator.java new file mode 100644 index 0000000..48dd949 --- /dev/null +++ b/src/gnu/trove/iterator/TObjectIntIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type Object and int. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TObjectIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TObjectIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TObjectIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TObjectIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: Object_E_Iterator.template,v 1.1.2.1 2009/09/14 19:02:20 upholderoftruth Exp $ + */ +public interface TObjectIntIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public K key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TObjectLongIterator.java b/src/gnu/trove/iterator/TObjectLongIterator.java new file mode 100644 index 0000000..315b1e8 --- /dev/null +++ b/src/gnu/trove/iterator/TObjectLongIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type Object and long. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TObjectLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TObjectLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TObjectLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TObjectLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: Object_E_Iterator.template,v 1.1.2.1 2009/09/14 19:02:20 upholderoftruth Exp $ + */ +public interface TObjectLongIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public K key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TObjectShortIterator.java b/src/gnu/trove/iterator/TObjectShortIterator.java new file mode 100644 index 0000000..8f65360 --- /dev/null +++ b/src/gnu/trove/iterator/TObjectShortIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type Object and short. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TObjectShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TObjectShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TObjectShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TObjectShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: Object_E_Iterator.template,v 1.1.2.1 2009/09/14 19:02:20 upholderoftruth Exp $ + */ +public interface TObjectShortIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public K key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/TPrimitiveIterator.java b/src/gnu/trove/iterator/TPrimitiveIterator.java new file mode 100644 index 0000000..5693c3a --- /dev/null +++ b/src/gnu/trove/iterator/TPrimitiveIterator.java @@ -0,0 +1,61 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +/** + * Implements all iterator functions for the hashed object set. + * Subclasses may override objectAtIndex to vary the object + * returned by calls to next() (e.g. for values, and Map.Entry + * objects). + *

+ *

Note that iteration is fastest if you forego the calls to + * hasNext in favor of checking the size of the structure + * yourself and then call next() that many times: + *

+ *

+ * Iterator i = collection.iterator();
+ * for (int size = collection.size(); size-- > 0;) {
+ *   Object o = i.next();
+ * }
+ * 
+ *

+ *

You may, of course, use the hasNext(), next() idiom too if + * you aren't in a performance critical spot.

+ */ +public interface TPrimitiveIterator extends TIterator { + /** + * Returns true if the iterator can be advanced past its current + * location. + * + * @return a boolean value + */ + public boolean hasNext(); + + + /** + * Removes the last entry returned by the iterator. + * Invoking this method more than once for a single entry + * will leave the underlying data structure in a confused + * state. + */ + public void remove(); + +} // TPrimitiveIterator diff --git a/src/gnu/trove/iterator/TShortByteIterator.java b/src/gnu/trove/iterator/TShortByteIterator.java new file mode 100644 index 0000000..663f987 --- /dev/null +++ b/src/gnu/trove/iterator/TShortByteIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and byte. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TShortByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TShortByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TShortByteIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TShortByteIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TShortByteIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public byte value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public byte setValue( byte val ); +} diff --git a/src/gnu/trove/iterator/TShortCharIterator.java b/src/gnu/trove/iterator/TShortCharIterator.java new file mode 100644 index 0000000..2188a26 --- /dev/null +++ b/src/gnu/trove/iterator/TShortCharIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and char. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TShortCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TShortCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TShortCharIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TShortCharIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TShortCharIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public char value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public char setValue( char val ); +} diff --git a/src/gnu/trove/iterator/TShortDoubleIterator.java b/src/gnu/trove/iterator/TShortDoubleIterator.java new file mode 100644 index 0000000..022fb0e --- /dev/null +++ b/src/gnu/trove/iterator/TShortDoubleIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and double. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TShortDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TShortDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TShortDoubleIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TShortDoubleIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TShortDoubleIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public double value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public double setValue( double val ); +} diff --git a/src/gnu/trove/iterator/TShortFloatIterator.java b/src/gnu/trove/iterator/TShortFloatIterator.java new file mode 100644 index 0000000..611cb95 --- /dev/null +++ b/src/gnu/trove/iterator/TShortFloatIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and float. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TShortFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TShortFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TShortFloatIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TShortFloatIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TShortFloatIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public float value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public float setValue( float val ); +} diff --git a/src/gnu/trove/iterator/TShortIntIterator.java b/src/gnu/trove/iterator/TShortIntIterator.java new file mode 100644 index 0000000..15c69ba --- /dev/null +++ b/src/gnu/trove/iterator/TShortIntIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and int. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TShortIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TShortIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TShortIntIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TShortIntIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TShortIntIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public int value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public int setValue( int val ); +} diff --git a/src/gnu/trove/iterator/TShortIterator.java b/src/gnu/trove/iterator/TShortIterator.java new file mode 100644 index 0000000..63724c2 --- /dev/null +++ b/src/gnu/trove/iterator/TShortIterator.java @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for short collections. + */ +public interface TShortIterator extends TIterator { + /** + * Advances the iterator to the next element in the underlying collection + * and returns it. + * + * @return the next short in the collection + * @exception NoSuchElementException if the iterator is already exhausted + */ + public short next(); +} diff --git a/src/gnu/trove/iterator/TShortLongIterator.java b/src/gnu/trove/iterator/TShortLongIterator.java new file mode 100644 index 0000000..d2b9ce4 --- /dev/null +++ b/src/gnu/trove/iterator/TShortLongIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and long. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TShortLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TShortLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TShortLongIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TShortLongIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TShortLongIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public long value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public long setValue( long val ); +} diff --git a/src/gnu/trove/iterator/TShortObjectIterator.java b/src/gnu/trove/iterator/TShortObjectIterator.java new file mode 100644 index 0000000..51e9686 --- /dev/null +++ b/src/gnu/trove/iterator/TShortObjectIterator.java @@ -0,0 +1,125 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and Object. + *

+ * The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al. + *

+ * This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time. + *

+ * In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger. + *

+ * Here are some sample scenarios for this class of iterator: + *

+ *

+ * // accessing keys/values through an iterator:
+ * for ( TShortObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // modifying values in-place through iteration:
+ * for ( TShortObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ *

+ *

+ * // deleting entries during iteration:
+ * for ( TShortObjectIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ *

+ *

+ * // faster iteration by avoiding hasNext():
+ * TShortObjectIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $ + */ +public interface TShortObjectIterator extends TAdvancingIterator { + + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public V value(); + + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public V setValue( V val ); +} diff --git a/src/gnu/trove/iterator/TShortShortIterator.java b/src/gnu/trove/iterator/TShortShortIterator.java new file mode 100644 index 0000000..2f30fb6 --- /dev/null +++ b/src/gnu/trove/iterator/TShortShortIterator.java @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.iterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Iterator for maps of type short and short. + * + *

The iterator semantics for Trove's primitive maps is slightly different + * from those defined in java.util.Iterator, but still well within + * the scope of the pattern, as defined by Gamma, et al.

+ * + *

This iterator does not implicitly advance to the next entry when + * the value at the current position is retrieved. Rather, you must explicitly + * ask the iterator to advance() and then retrieve either the key(), + * the value() or both. This is done so that you have the option, but not + * the obligation, to retrieve keys and/or values as your application requires, and + * without introducing wrapper objects that would carry both. As the iteration is + * stateful, access to the key/value parts of the current map entry happens in + * constant time.

+ * + *

In practice, the iterator is akin to a "search finger" that you move from + * position to position. Read or write operations affect the current entry only and + * do not assume responsibility for moving the finger.

+ * + *

Here are some sample scenarios for this class of iterator:

+ * + *
+ * // accessing keys/values through an iterator:
+ * for ( TShortShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     doSomethingWithValue( it.value() );
+ *   }
+ * }
+ * 
+ * + *
+ * // modifying values in-place through iteration:
+ * for ( TShortShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.setValue( newValueForKey( it.key() ) );
+ *   }
+ * }
+ * 
+ * + *
+ * // deleting entries during iteration:
+ * for ( TShortShortIterator it = map.iterator(); it.hasNext(); ) {
+ *   it.advance();
+ *   if ( satisfiesCondition( it.key() ) {
+ *     it.remove();
+ *   }
+ * }
+ * 
+ * + *
+ * // faster iteration by avoiding hasNext():
+ * TShortShortIterator iterator = map.iterator();
+ * for ( int i = map.size(); i-- > 0; ) {
+ *   iterator.advance();
+ *   doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
+ * }
+ * 
+ */ +public interface TShortShortIterator extends TAdvancingIterator { + /** + * Provides access to the key of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the key of the entry at the iterator's current position. + */ + public short key(); + + /** + * Provides access to the value of the mapping at the iterator's position. + * Note that you must advance() the iterator at least once + * before invoking this method. + * + * @return the value of the entry at the iterator's current position. + */ + public short value(); + + /** + * Replace the value of the mapping at the iterator's position with the + * specified value. Note that you must advance() the iterator at + * least once before invoking this method. + * + * @param val the value to set in the current entry + * @return the old value of the entry. + */ + public short setValue( short val ); +} diff --git a/src/gnu/trove/iterator/hash/TObjectHashIterator.java b/src/gnu/trove/iterator/hash/TObjectHashIterator.java new file mode 100644 index 0000000..75895d0 --- /dev/null +++ b/src/gnu/trove/iterator/hash/TObjectHashIterator.java @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.iterator.hash; + +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.impl.hash.THashIterator; + + +/** + * Iterator for hashtables that use open addressing to resolve collisions. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: TObjectHashIterator.java,v 1.1.2.4 2009/10/09 01:44:34 robeden Exp $ + */ + +public class TObjectHashIterator extends THashIterator { + + protected final TObjectHash _objectHash; + + + public TObjectHashIterator( TObjectHash hash ) { + super( hash ); + _objectHash = hash; + } + + + @SuppressWarnings("unchecked") + protected E objectAtIndex( int index ) { + Object obj = _objectHash._set[index]; + if ( obj == TObjectHash.FREE || obj == TObjectHash.REMOVED ) { + return null; + } + return (E) obj; + } + +} // TObjectHashIterator diff --git a/src/gnu/trove/list/TByteList.java b/src/gnu/trove/list/TByteList.java new file mode 100644 index 0000000..5ca1127 --- /dev/null +++ b/src/gnu/trove/list/TByteList.java @@ -0,0 +1,513 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +import java.util.Random; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TByteFunction; +import gnu.trove.procedure.TByteProcedure; + + + +/** + * Interface for Trove list implementations. + */ +public interface TByteList extends TByteCollection { + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue(); + + + /** + * Returns the number of values in the list. + * + * @return the number of values in the list. + */ + public int size(); + + + /** + * Tests whether this list contains any values. + * + * @return true if the list is empty. + */ + public boolean isEmpty(); + + + /** + * Adds val to the end of the list, growing as needed. + * + * @param val an byte value + * @return true if the list was modified by the add operation + */ + public boolean add(byte val); + + + /** + * Adds the values in the array vals to the end of the + * list, in order. + * + * @param vals an byte[] value + */ + public void add( byte[] vals ); + + + /** + * Adds a subset of the values in the array vals to the + * end of the list, in order. + * + * @param vals an byte[] value + * @param offset the offset at which to start copying + * @param length the number of values to copy. + */ + public void add( byte[] vals, int offset, int length ); + + + /** + * Inserts value into the list at offset. All + * values including and to the right of offset are shifted + * to the right. + * + * @param offset an int value + * @param value an byte value + */ + public void insert( int offset, byte value ); + + + /** + * Inserts the array of values into the list at + * offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an byte[] value + */ + public void insert( int offset, byte[] values ); + + + /** + * Inserts a slice of the array of values into the list + * at offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an byte[] value + * @param valOffset the offset in the values array at which to + * start copying. + * @param len the number of values to copy from the values array + */ + public void insert( int offset, byte[] values, int valOffset, int len ); + + + /** + * Returns the value at the specified offset. + * + * @param offset an int value + * @return an byte value + */ + public byte get( int offset ); + + + /** + * Sets the value at the specified offset. + * + * @param offset an int value + * @param val an byte value + * + * @return The value previously at the given index. + */ + public byte set( int offset, byte val ); + + + /** + * Replace the values in the list starting at offset with + * the contents of the values array. + * + * @param offset the first offset to replace + * @param values the source of the new values + */ + public void set( int offset, byte[] values ); + + + /** + * Replace the values in the list starting at offset with + * length values from the values array, starting + * at valOffset. + * + * @param offset the first offset to replace + * @param values the source of the new values + * @param valOffset the first value to copy from the values array + * @param length the number of values to copy + */ + public void set( int offset, byte[] values, int valOffset, int length ); + + + /** + * Sets the value at the specified offset and returns the + * previously stored value. + * + * @param offset an int value + * @param val an byte value + * @return the value previously stored at offset. + */ + public byte replace( int offset, byte val ); + + + /** + * Flushes the internal state of the list, resetting the capacity + * to the default. + */ + public void clear(); + + + /** + * Removes value from the list. + * + * @param value an byte value + * @return true if the list was modified by the remove operation. + */ + public boolean remove( byte value ); + + + /** + * Removes value at a given offset from the list. + * + * @param offset an int value that represents + * the offset to the element to be removed + * @return an byte that is the value removed. + */ + public byte removeAt( int offset ); + + + /** + * Removes length values from the list, starting at + * offset + * + * @param offset an int value + * @param length an int value + */ + public void remove( int offset, int length ); + + + /** + * Transform each value in the list using the specified function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Reverse the order of the elements in the list. + */ + public void reverse(); + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + public void reverse( int from, int to ); + + + /** + * Shuffle the elements of the list using the specified random + * number generator. + * + * @param rand a Random value + */ + public void shuffle( Random rand ); + + + /** + * Returns a sublist of this list. + * + * @param begin low endpoint (inclusive) of the subList. + * @param end high endpoint (exclusive) of the subList. + * @return sublist of this list from begin, inclusive to end, exclusive. + * @throws IndexOutOfBoundsException - endpoint out of range + * @throws IllegalArgumentException - endpoints out of order (end > begin) + */ + public TByteList subList( int begin, int end ); + + + /** + * Copies the contents of the list into a native array. + * + * @return an byte[] value + */ + public byte[] toArray(); + + + /** + * Copies a slice of the list into a native array. + * + * @param offset the offset at which to start copying + * @param len the number of values to copy. + * @return an byte[] value + */ + public byte[] toArray( int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to + * {@link #getNoEntryValue()}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any "null" elements.) + * + *

NOTE: Trove does not allocate a new array if the array passed in is + * not large enough to hold all of the data elements. It will instead fill + * the array passed in. + * + * @param dest the array to copy into. + * @return the array passed in. + */ + public byte[] toArray( byte[] dest ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param offset the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public byte[] toArray( byte[] dest, int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param source_pos the offset of the first value to copy + * @param dest_pos the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public byte[] toArray( byte[] dest, int source_pos, int dest_pos, int len ); + + + /** + * Applies the procedure to each value in the list in ascending + * (front to back) order. + * + * @param procedure a TByteProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEach( TByteProcedure procedure ); + + + /** + * Applies the procedure to each value in the list in descending + * (back to front) order. + * + * @param procedure a TByteProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEachDescending( TByteProcedure procedure ); + + + /** + * Sort the values in the list (ascending) using the Sun quicksort + * implementation. + * + * @see java.util.Arrays#sort + */ + public void sort(); + + + /** + * Sort a slice of the list (ascending) using the Sun quicksort + * implementation. + * + * @param fromIndex the index at which to start sorting (inclusive) + * @param toIndex the index at which to stop sorting (exclusive) + * @see java.util.Arrays#sort + */ + public void sort( int fromIndex, int toIndex ); + + + /** + * Fills every slot in the list with the specified value. + * + * @param val the value to use when filling + */ + public void fill( byte val ); + + + /** + * Fills a range in the list with the specified value. + * + * @param fromIndex the offset at which to start filling (inclusive) + * @param toIndex the offset at which to stop filling (exclusive) + * @param val the value to use when filling + */ + public void fill( int fromIndex, int toIndex, byte val ); + + + /** + * Performs a binary search for value in the entire list. + * Note that you must @{link #sort sort} the list before + * doing a search. + * + * @param value the value to search for + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( byte value ); + + + /** + * Performs a binary search for value in the specified + * range. Note that you must @{link #sort sort} the list + * or the range before doing a search. + * + * @param value the value to search for + * @param fromIndex the lower boundary of the range (inclusive) + * @param toIndex the upper boundary of the range (exclusive) + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( byte value, int fromIndex, int toIndex ); + + + /** + * Searches the list front to back for the index of + * value. + * + * @param value an byte value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( byte value ); + + + /** + * Searches the list front to back for the index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (inclusive) + * @param value an byte value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int offset, byte value ); + + + /** + * Searches the list back to front for the last index of + * value. + * + * @param value an byte value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( byte value ); + + + /** + * Searches the list back to front for the last index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (exclusive) + * @param value an byte value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int offset, byte value ); + + + /** + * Searches the list for value + * + * @param value an byte value + * @return true if value is in the list. + */ + public boolean contains( byte value ); + + + /** + * Searches the list for values satisfying condition in + * the manner of the *nix grep utility. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which match the condition. + */ + public TByteList grep( TByteProcedure condition ); + + + /** + * Searches the list for values which do not satisfy + * condition. This is akin to *nix grep -v. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which do not match the condition. + */ + public TByteList inverseGrep( TByteProcedure condition ); + + + /** + * Finds the maximum value in the list. + * + * @return the largest value in the list. + * @exception IllegalStateException if the list is empty + */ + public byte max(); + + + /** + * Finds the minimum value in the list. + * + * @return the smallest value in the list. + * @exception IllegalStateException if the list is empty + */ + public byte min(); + + + /** + * Calculates the sum of all the values in the list. + * + * @return the sum of the values in the list (zero if the list is empty). + */ + public byte sum(); +} diff --git a/src/gnu/trove/list/TCharList.java b/src/gnu/trove/list/TCharList.java new file mode 100644 index 0000000..dfc6c53 --- /dev/null +++ b/src/gnu/trove/list/TCharList.java @@ -0,0 +1,513 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +import java.util.Random; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TCharFunction; +import gnu.trove.procedure.TCharProcedure; + + + +/** + * Interface for Trove list implementations. + */ +public interface TCharList extends TCharCollection { + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue(); + + + /** + * Returns the number of values in the list. + * + * @return the number of values in the list. + */ + public int size(); + + + /** + * Tests whether this list contains any values. + * + * @return true if the list is empty. + */ + public boolean isEmpty(); + + + /** + * Adds val to the end of the list, growing as needed. + * + * @param val an char value + * @return true if the list was modified by the add operation + */ + public boolean add(char val); + + + /** + * Adds the values in the array vals to the end of the + * list, in order. + * + * @param vals an char[] value + */ + public void add( char[] vals ); + + + /** + * Adds a subset of the values in the array vals to the + * end of the list, in order. + * + * @param vals an char[] value + * @param offset the offset at which to start copying + * @param length the number of values to copy. + */ + public void add( char[] vals, int offset, int length ); + + + /** + * Inserts value into the list at offset. All + * values including and to the right of offset are shifted + * to the right. + * + * @param offset an int value + * @param value an char value + */ + public void insert( int offset, char value ); + + + /** + * Inserts the array of values into the list at + * offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an char[] value + */ + public void insert( int offset, char[] values ); + + + /** + * Inserts a slice of the array of values into the list + * at offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an char[] value + * @param valOffset the offset in the values array at which to + * start copying. + * @param len the number of values to copy from the values array + */ + public void insert( int offset, char[] values, int valOffset, int len ); + + + /** + * Returns the value at the specified offset. + * + * @param offset an int value + * @return an char value + */ + public char get( int offset ); + + + /** + * Sets the value at the specified offset. + * + * @param offset an int value + * @param val an char value + * + * @return The value previously at the given index. + */ + public char set( int offset, char val ); + + + /** + * Replace the values in the list starting at offset with + * the contents of the values array. + * + * @param offset the first offset to replace + * @param values the source of the new values + */ + public void set( int offset, char[] values ); + + + /** + * Replace the values in the list starting at offset with + * length values from the values array, starting + * at valOffset. + * + * @param offset the first offset to replace + * @param values the source of the new values + * @param valOffset the first value to copy from the values array + * @param length the number of values to copy + */ + public void set( int offset, char[] values, int valOffset, int length ); + + + /** + * Sets the value at the specified offset and returns the + * previously stored value. + * + * @param offset an int value + * @param val an char value + * @return the value previously stored at offset. + */ + public char replace( int offset, char val ); + + + /** + * Flushes the internal state of the list, resetting the capacity + * to the default. + */ + public void clear(); + + + /** + * Removes value from the list. + * + * @param value an char value + * @return true if the list was modified by the remove operation. + */ + public boolean remove( char value ); + + + /** + * Removes value at a given offset from the list. + * + * @param offset an int value that represents + * the offset to the element to be removed + * @return an char that is the value removed. + */ + public char removeAt( int offset ); + + + /** + * Removes length values from the list, starting at + * offset + * + * @param offset an int value + * @param length an int value + */ + public void remove( int offset, int length ); + + + /** + * Transform each value in the list using the specified function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Reverse the order of the elements in the list. + */ + public void reverse(); + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + public void reverse( int from, int to ); + + + /** + * Shuffle the elements of the list using the specified random + * number generator. + * + * @param rand a Random value + */ + public void shuffle( Random rand ); + + + /** + * Returns a sublist of this list. + * + * @param begin low endpoint (inclusive) of the subList. + * @param end high endpoint (exclusive) of the subList. + * @return sublist of this list from begin, inclusive to end, exclusive. + * @throws IndexOutOfBoundsException - endpoint out of range + * @throws IllegalArgumentException - endpoints out of order (end > begin) + */ + public TCharList subList( int begin, int end ); + + + /** + * Copies the contents of the list into a native array. + * + * @return an char[] value + */ + public char[] toArray(); + + + /** + * Copies a slice of the list into a native array. + * + * @param offset the offset at which to start copying + * @param len the number of values to copy. + * @return an char[] value + */ + public char[] toArray( int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to + * {@link #getNoEntryValue()}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any "null" elements.) + * + *

NOTE: Trove does not allocate a new array if the array passed in is + * not large enough to hold all of the data elements. It will instead fill + * the array passed in. + * + * @param dest the array to copy into. + * @return the array passed in. + */ + public char[] toArray( char[] dest ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param offset the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public char[] toArray( char[] dest, int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param source_pos the offset of the first value to copy + * @param dest_pos the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public char[] toArray( char[] dest, int source_pos, int dest_pos, int len ); + + + /** + * Applies the procedure to each value in the list in ascending + * (front to back) order. + * + * @param procedure a TCharProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEach( TCharProcedure procedure ); + + + /** + * Applies the procedure to each value in the list in descending + * (back to front) order. + * + * @param procedure a TCharProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEachDescending( TCharProcedure procedure ); + + + /** + * Sort the values in the list (ascending) using the Sun quicksort + * implementation. + * + * @see java.util.Arrays#sort + */ + public void sort(); + + + /** + * Sort a slice of the list (ascending) using the Sun quicksort + * implementation. + * + * @param fromIndex the index at which to start sorting (inclusive) + * @param toIndex the index at which to stop sorting (exclusive) + * @see java.util.Arrays#sort + */ + public void sort( int fromIndex, int toIndex ); + + + /** + * Fills every slot in the list with the specified value. + * + * @param val the value to use when filling + */ + public void fill( char val ); + + + /** + * Fills a range in the list with the specified value. + * + * @param fromIndex the offset at which to start filling (inclusive) + * @param toIndex the offset at which to stop filling (exclusive) + * @param val the value to use when filling + */ + public void fill( int fromIndex, int toIndex, char val ); + + + /** + * Performs a binary search for value in the entire list. + * Note that you must @{link #sort sort} the list before + * doing a search. + * + * @param value the value to search for + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( char value ); + + + /** + * Performs a binary search for value in the specified + * range. Note that you must @{link #sort sort} the list + * or the range before doing a search. + * + * @param value the value to search for + * @param fromIndex the lower boundary of the range (inclusive) + * @param toIndex the upper boundary of the range (exclusive) + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( char value, int fromIndex, int toIndex ); + + + /** + * Searches the list front to back for the index of + * value. + * + * @param value an char value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( char value ); + + + /** + * Searches the list front to back for the index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (inclusive) + * @param value an char value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int offset, char value ); + + + /** + * Searches the list back to front for the last index of + * value. + * + * @param value an char value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( char value ); + + + /** + * Searches the list back to front for the last index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (exclusive) + * @param value an char value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int offset, char value ); + + + /** + * Searches the list for value + * + * @param value an char value + * @return true if value is in the list. + */ + public boolean contains( char value ); + + + /** + * Searches the list for values satisfying condition in + * the manner of the *nix grep utility. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which match the condition. + */ + public TCharList grep( TCharProcedure condition ); + + + /** + * Searches the list for values which do not satisfy + * condition. This is akin to *nix grep -v. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which do not match the condition. + */ + public TCharList inverseGrep( TCharProcedure condition ); + + + /** + * Finds the maximum value in the list. + * + * @return the largest value in the list. + * @exception IllegalStateException if the list is empty + */ + public char max(); + + + /** + * Finds the minimum value in the list. + * + * @return the smallest value in the list. + * @exception IllegalStateException if the list is empty + */ + public char min(); + + + /** + * Calculates the sum of all the values in the list. + * + * @return the sum of the values in the list (zero if the list is empty). + */ + public char sum(); +} diff --git a/src/gnu/trove/list/TDoubleList.java b/src/gnu/trove/list/TDoubleList.java new file mode 100644 index 0000000..46a79a5 --- /dev/null +++ b/src/gnu/trove/list/TDoubleList.java @@ -0,0 +1,513 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +import java.util.Random; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TDoubleFunction; +import gnu.trove.procedure.TDoubleProcedure; + + + +/** + * Interface for Trove list implementations. + */ +public interface TDoubleList extends TDoubleCollection { + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue(); + + + /** + * Returns the number of values in the list. + * + * @return the number of values in the list. + */ + public int size(); + + + /** + * Tests whether this list contains any values. + * + * @return true if the list is empty. + */ + public boolean isEmpty(); + + + /** + * Adds val to the end of the list, growing as needed. + * + * @param val an double value + * @return true if the list was modified by the add operation + */ + public boolean add(double val); + + + /** + * Adds the values in the array vals to the end of the + * list, in order. + * + * @param vals an double[] value + */ + public void add( double[] vals ); + + + /** + * Adds a subset of the values in the array vals to the + * end of the list, in order. + * + * @param vals an double[] value + * @param offset the offset at which to start copying + * @param length the number of values to copy. + */ + public void add( double[] vals, int offset, int length ); + + + /** + * Inserts value into the list at offset. All + * values including and to the right of offset are shifted + * to the right. + * + * @param offset an int value + * @param value an double value + */ + public void insert( int offset, double value ); + + + /** + * Inserts the array of values into the list at + * offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an double[] value + */ + public void insert( int offset, double[] values ); + + + /** + * Inserts a slice of the array of values into the list + * at offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an double[] value + * @param valOffset the offset in the values array at which to + * start copying. + * @param len the number of values to copy from the values array + */ + public void insert( int offset, double[] values, int valOffset, int len ); + + + /** + * Returns the value at the specified offset. + * + * @param offset an int value + * @return an double value + */ + public double get( int offset ); + + + /** + * Sets the value at the specified offset. + * + * @param offset an int value + * @param val an double value + * + * @return The value previously at the given index. + */ + public double set( int offset, double val ); + + + /** + * Replace the values in the list starting at offset with + * the contents of the values array. + * + * @param offset the first offset to replace + * @param values the source of the new values + */ + public void set( int offset, double[] values ); + + + /** + * Replace the values in the list starting at offset with + * length values from the values array, starting + * at valOffset. + * + * @param offset the first offset to replace + * @param values the source of the new values + * @param valOffset the first value to copy from the values array + * @param length the number of values to copy + */ + public void set( int offset, double[] values, int valOffset, int length ); + + + /** + * Sets the value at the specified offset and returns the + * previously stored value. + * + * @param offset an int value + * @param val an double value + * @return the value previously stored at offset. + */ + public double replace( int offset, double val ); + + + /** + * Flushes the internal state of the list, resetting the capacity + * to the default. + */ + public void clear(); + + + /** + * Removes value from the list. + * + * @param value an double value + * @return true if the list was modified by the remove operation. + */ + public boolean remove( double value ); + + + /** + * Removes value at a given offset from the list. + * + * @param offset an int value that represents + * the offset to the element to be removed + * @return an double that is the value removed. + */ + public double removeAt( int offset ); + + + /** + * Removes length values from the list, starting at + * offset + * + * @param offset an int value + * @param length an int value + */ + public void remove( int offset, int length ); + + + /** + * Transform each value in the list using the specified function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Reverse the order of the elements in the list. + */ + public void reverse(); + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + public void reverse( int from, int to ); + + + /** + * Shuffle the elements of the list using the specified random + * number generator. + * + * @param rand a Random value + */ + public void shuffle( Random rand ); + + + /** + * Returns a sublist of this list. + * + * @param begin low endpoint (inclusive) of the subList. + * @param end high endpoint (exclusive) of the subList. + * @return sublist of this list from begin, inclusive to end, exclusive. + * @throws IndexOutOfBoundsException - endpoint out of range + * @throws IllegalArgumentException - endpoints out of order (end > begin) + */ + public TDoubleList subList( int begin, int end ); + + + /** + * Copies the contents of the list into a native array. + * + * @return an double[] value + */ + public double[] toArray(); + + + /** + * Copies a slice of the list into a native array. + * + * @param offset the offset at which to start copying + * @param len the number of values to copy. + * @return an double[] value + */ + public double[] toArray( int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to + * {@link #getNoEntryValue()}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any "null" elements.) + * + *

NOTE: Trove does not allocate a new array if the array passed in is + * not large enough to hold all of the data elements. It will instead fill + * the array passed in. + * + * @param dest the array to copy into. + * @return the array passed in. + */ + public double[] toArray( double[] dest ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param offset the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public double[] toArray( double[] dest, int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param source_pos the offset of the first value to copy + * @param dest_pos the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public double[] toArray( double[] dest, int source_pos, int dest_pos, int len ); + + + /** + * Applies the procedure to each value in the list in ascending + * (front to back) order. + * + * @param procedure a TDoubleProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEach( TDoubleProcedure procedure ); + + + /** + * Applies the procedure to each value in the list in descending + * (back to front) order. + * + * @param procedure a TDoubleProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEachDescending( TDoubleProcedure procedure ); + + + /** + * Sort the values in the list (ascending) using the Sun quicksort + * implementation. + * + * @see java.util.Arrays#sort + */ + public void sort(); + + + /** + * Sort a slice of the list (ascending) using the Sun quicksort + * implementation. + * + * @param fromIndex the index at which to start sorting (inclusive) + * @param toIndex the index at which to stop sorting (exclusive) + * @see java.util.Arrays#sort + */ + public void sort( int fromIndex, int toIndex ); + + + /** + * Fills every slot in the list with the specified value. + * + * @param val the value to use when filling + */ + public void fill( double val ); + + + /** + * Fills a range in the list with the specified value. + * + * @param fromIndex the offset at which to start filling (inclusive) + * @param toIndex the offset at which to stop filling (exclusive) + * @param val the value to use when filling + */ + public void fill( int fromIndex, int toIndex, double val ); + + + /** + * Performs a binary search for value in the entire list. + * Note that you must @{link #sort sort} the list before + * doing a search. + * + * @param value the value to search for + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( double value ); + + + /** + * Performs a binary search for value in the specified + * range. Note that you must @{link #sort sort} the list + * or the range before doing a search. + * + * @param value the value to search for + * @param fromIndex the lower boundary of the range (inclusive) + * @param toIndex the upper boundary of the range (exclusive) + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( double value, int fromIndex, int toIndex ); + + + /** + * Searches the list front to back for the index of + * value. + * + * @param value an double value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( double value ); + + + /** + * Searches the list front to back for the index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (inclusive) + * @param value an double value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int offset, double value ); + + + /** + * Searches the list back to front for the last index of + * value. + * + * @param value an double value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( double value ); + + + /** + * Searches the list back to front for the last index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (exclusive) + * @param value an double value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int offset, double value ); + + + /** + * Searches the list for value + * + * @param value an double value + * @return true if value is in the list. + */ + public boolean contains( double value ); + + + /** + * Searches the list for values satisfying condition in + * the manner of the *nix grep utility. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which match the condition. + */ + public TDoubleList grep( TDoubleProcedure condition ); + + + /** + * Searches the list for values which do not satisfy + * condition. This is akin to *nix grep -v. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which do not match the condition. + */ + public TDoubleList inverseGrep( TDoubleProcedure condition ); + + + /** + * Finds the maximum value in the list. + * + * @return the largest value in the list. + * @exception IllegalStateException if the list is empty + */ + public double max(); + + + /** + * Finds the minimum value in the list. + * + * @return the smallest value in the list. + * @exception IllegalStateException if the list is empty + */ + public double min(); + + + /** + * Calculates the sum of all the values in the list. + * + * @return the sum of the values in the list (zero if the list is empty). + */ + public double sum(); +} diff --git a/src/gnu/trove/list/TFloatList.java b/src/gnu/trove/list/TFloatList.java new file mode 100644 index 0000000..e55aa63 --- /dev/null +++ b/src/gnu/trove/list/TFloatList.java @@ -0,0 +1,513 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +import java.util.Random; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TFloatFunction; +import gnu.trove.procedure.TFloatProcedure; + + + +/** + * Interface for Trove list implementations. + */ +public interface TFloatList extends TFloatCollection { + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue(); + + + /** + * Returns the number of values in the list. + * + * @return the number of values in the list. + */ + public int size(); + + + /** + * Tests whether this list contains any values. + * + * @return true if the list is empty. + */ + public boolean isEmpty(); + + + /** + * Adds val to the end of the list, growing as needed. + * + * @param val an float value + * @return true if the list was modified by the add operation + */ + public boolean add(float val); + + + /** + * Adds the values in the array vals to the end of the + * list, in order. + * + * @param vals an float[] value + */ + public void add( float[] vals ); + + + /** + * Adds a subset of the values in the array vals to the + * end of the list, in order. + * + * @param vals an float[] value + * @param offset the offset at which to start copying + * @param length the number of values to copy. + */ + public void add( float[] vals, int offset, int length ); + + + /** + * Inserts value into the list at offset. All + * values including and to the right of offset are shifted + * to the right. + * + * @param offset an int value + * @param value an float value + */ + public void insert( int offset, float value ); + + + /** + * Inserts the array of values into the list at + * offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an float[] value + */ + public void insert( int offset, float[] values ); + + + /** + * Inserts a slice of the array of values into the list + * at offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an float[] value + * @param valOffset the offset in the values array at which to + * start copying. + * @param len the number of values to copy from the values array + */ + public void insert( int offset, float[] values, int valOffset, int len ); + + + /** + * Returns the value at the specified offset. + * + * @param offset an int value + * @return an float value + */ + public float get( int offset ); + + + /** + * Sets the value at the specified offset. + * + * @param offset an int value + * @param val an float value + * + * @return The value previously at the given index. + */ + public float set( int offset, float val ); + + + /** + * Replace the values in the list starting at offset with + * the contents of the values array. + * + * @param offset the first offset to replace + * @param values the source of the new values + */ + public void set( int offset, float[] values ); + + + /** + * Replace the values in the list starting at offset with + * length values from the values array, starting + * at valOffset. + * + * @param offset the first offset to replace + * @param values the source of the new values + * @param valOffset the first value to copy from the values array + * @param length the number of values to copy + */ + public void set( int offset, float[] values, int valOffset, int length ); + + + /** + * Sets the value at the specified offset and returns the + * previously stored value. + * + * @param offset an int value + * @param val an float value + * @return the value previously stored at offset. + */ + public float replace( int offset, float val ); + + + /** + * Flushes the internal state of the list, resetting the capacity + * to the default. + */ + public void clear(); + + + /** + * Removes value from the list. + * + * @param value an float value + * @return true if the list was modified by the remove operation. + */ + public boolean remove( float value ); + + + /** + * Removes value at a given offset from the list. + * + * @param offset an int value that represents + * the offset to the element to be removed + * @return an float that is the value removed. + */ + public float removeAt( int offset ); + + + /** + * Removes length values from the list, starting at + * offset + * + * @param offset an int value + * @param length an int value + */ + public void remove( int offset, int length ); + + + /** + * Transform each value in the list using the specified function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Reverse the order of the elements in the list. + */ + public void reverse(); + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + public void reverse( int from, int to ); + + + /** + * Shuffle the elements of the list using the specified random + * number generator. + * + * @param rand a Random value + */ + public void shuffle( Random rand ); + + + /** + * Returns a sublist of this list. + * + * @param begin low endpoint (inclusive) of the subList. + * @param end high endpoint (exclusive) of the subList. + * @return sublist of this list from begin, inclusive to end, exclusive. + * @throws IndexOutOfBoundsException - endpoint out of range + * @throws IllegalArgumentException - endpoints out of order (end > begin) + */ + public TFloatList subList( int begin, int end ); + + + /** + * Copies the contents of the list into a native array. + * + * @return an float[] value + */ + public float[] toArray(); + + + /** + * Copies a slice of the list into a native array. + * + * @param offset the offset at which to start copying + * @param len the number of values to copy. + * @return an float[] value + */ + public float[] toArray( int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to + * {@link #getNoEntryValue()}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any "null" elements.) + * + *

NOTE: Trove does not allocate a new array if the array passed in is + * not large enough to hold all of the data elements. It will instead fill + * the array passed in. + * + * @param dest the array to copy into. + * @return the array passed in. + */ + public float[] toArray( float[] dest ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param offset the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public float[] toArray( float[] dest, int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param source_pos the offset of the first value to copy + * @param dest_pos the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public float[] toArray( float[] dest, int source_pos, int dest_pos, int len ); + + + /** + * Applies the procedure to each value in the list in ascending + * (front to back) order. + * + * @param procedure a TFloatProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEach( TFloatProcedure procedure ); + + + /** + * Applies the procedure to each value in the list in descending + * (back to front) order. + * + * @param procedure a TFloatProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEachDescending( TFloatProcedure procedure ); + + + /** + * Sort the values in the list (ascending) using the Sun quicksort + * implementation. + * + * @see java.util.Arrays#sort + */ + public void sort(); + + + /** + * Sort a slice of the list (ascending) using the Sun quicksort + * implementation. + * + * @param fromIndex the index at which to start sorting (inclusive) + * @param toIndex the index at which to stop sorting (exclusive) + * @see java.util.Arrays#sort + */ + public void sort( int fromIndex, int toIndex ); + + + /** + * Fills every slot in the list with the specified value. + * + * @param val the value to use when filling + */ + public void fill( float val ); + + + /** + * Fills a range in the list with the specified value. + * + * @param fromIndex the offset at which to start filling (inclusive) + * @param toIndex the offset at which to stop filling (exclusive) + * @param val the value to use when filling + */ + public void fill( int fromIndex, int toIndex, float val ); + + + /** + * Performs a binary search for value in the entire list. + * Note that you must @{link #sort sort} the list before + * doing a search. + * + * @param value the value to search for + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( float value ); + + + /** + * Performs a binary search for value in the specified + * range. Note that you must @{link #sort sort} the list + * or the range before doing a search. + * + * @param value the value to search for + * @param fromIndex the lower boundary of the range (inclusive) + * @param toIndex the upper boundary of the range (exclusive) + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( float value, int fromIndex, int toIndex ); + + + /** + * Searches the list front to back for the index of + * value. + * + * @param value an float value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( float value ); + + + /** + * Searches the list front to back for the index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (inclusive) + * @param value an float value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int offset, float value ); + + + /** + * Searches the list back to front for the last index of + * value. + * + * @param value an float value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( float value ); + + + /** + * Searches the list back to front for the last index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (exclusive) + * @param value an float value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int offset, float value ); + + + /** + * Searches the list for value + * + * @param value an float value + * @return true if value is in the list. + */ + public boolean contains( float value ); + + + /** + * Searches the list for values satisfying condition in + * the manner of the *nix grep utility. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which match the condition. + */ + public TFloatList grep( TFloatProcedure condition ); + + + /** + * Searches the list for values which do not satisfy + * condition. This is akin to *nix grep -v. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which do not match the condition. + */ + public TFloatList inverseGrep( TFloatProcedure condition ); + + + /** + * Finds the maximum value in the list. + * + * @return the largest value in the list. + * @exception IllegalStateException if the list is empty + */ + public float max(); + + + /** + * Finds the minimum value in the list. + * + * @return the smallest value in the list. + * @exception IllegalStateException if the list is empty + */ + public float min(); + + + /** + * Calculates the sum of all the values in the list. + * + * @return the sum of the values in the list (zero if the list is empty). + */ + public float sum(); +} diff --git a/src/gnu/trove/list/TIntList.java b/src/gnu/trove/list/TIntList.java new file mode 100644 index 0000000..e64ce06 --- /dev/null +++ b/src/gnu/trove/list/TIntList.java @@ -0,0 +1,513 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +import java.util.Random; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TIntFunction; +import gnu.trove.procedure.TIntProcedure; + + + +/** + * Interface for Trove list implementations. + */ +public interface TIntList extends TIntCollection { + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue(); + + + /** + * Returns the number of values in the list. + * + * @return the number of values in the list. + */ + public int size(); + + + /** + * Tests whether this list contains any values. + * + * @return true if the list is empty. + */ + public boolean isEmpty(); + + + /** + * Adds val to the end of the list, growing as needed. + * + * @param val an int value + * @return true if the list was modified by the add operation + */ + public boolean add(int val); + + + /** + * Adds the values in the array vals to the end of the + * list, in order. + * + * @param vals an int[] value + */ + public void add( int[] vals ); + + + /** + * Adds a subset of the values in the array vals to the + * end of the list, in order. + * + * @param vals an int[] value + * @param offset the offset at which to start copying + * @param length the number of values to copy. + */ + public void add( int[] vals, int offset, int length ); + + + /** + * Inserts value into the list at offset. All + * values including and to the right of offset are shifted + * to the right. + * + * @param offset an int value + * @param value an int value + */ + public void insert( int offset, int value ); + + + /** + * Inserts the array of values into the list at + * offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an int[] value + */ + public void insert( int offset, int[] values ); + + + /** + * Inserts a slice of the array of values into the list + * at offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an int[] value + * @param valOffset the offset in the values array at which to + * start copying. + * @param len the number of values to copy from the values array + */ + public void insert( int offset, int[] values, int valOffset, int len ); + + + /** + * Returns the value at the specified offset. + * + * @param offset an int value + * @return an int value + */ + public int get( int offset ); + + + /** + * Sets the value at the specified offset. + * + * @param offset an int value + * @param val an int value + * + * @return The value previously at the given index. + */ + public int set( int offset, int val ); + + + /** + * Replace the values in the list starting at offset with + * the contents of the values array. + * + * @param offset the first offset to replace + * @param values the source of the new values + */ + public void set( int offset, int[] values ); + + + /** + * Replace the values in the list starting at offset with + * length values from the values array, starting + * at valOffset. + * + * @param offset the first offset to replace + * @param values the source of the new values + * @param valOffset the first value to copy from the values array + * @param length the number of values to copy + */ + public void set( int offset, int[] values, int valOffset, int length ); + + + /** + * Sets the value at the specified offset and returns the + * previously stored value. + * + * @param offset an int value + * @param val an int value + * @return the value previously stored at offset. + */ + public int replace( int offset, int val ); + + + /** + * Flushes the internal state of the list, resetting the capacity + * to the default. + */ + public void clear(); + + + /** + * Removes value from the list. + * + * @param value an int value + * @return true if the list was modified by the remove operation. + */ + public boolean remove( int value ); + + + /** + * Removes value at a given offset from the list. + * + * @param offset an int value that represents + * the offset to the element to be removed + * @return an int that is the value removed. + */ + public int removeAt( int offset ); + + + /** + * Removes length values from the list, starting at + * offset + * + * @param offset an int value + * @param length an int value + */ + public void remove( int offset, int length ); + + + /** + * Transform each value in the list using the specified function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Reverse the order of the elements in the list. + */ + public void reverse(); + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + public void reverse( int from, int to ); + + + /** + * Shuffle the elements of the list using the specified random + * number generator. + * + * @param rand a Random value + */ + public void shuffle( Random rand ); + + + /** + * Returns a sublist of this list. + * + * @param begin low endpoint (inclusive) of the subList. + * @param end high endpoint (exclusive) of the subList. + * @return sublist of this list from begin, inclusive to end, exclusive. + * @throws IndexOutOfBoundsException - endpoint out of range + * @throws IllegalArgumentException - endpoints out of order (end > begin) + */ + public TIntList subList( int begin, int end ); + + + /** + * Copies the contents of the list into a native array. + * + * @return an int[] value + */ + public int[] toArray(); + + + /** + * Copies a slice of the list into a native array. + * + * @param offset the offset at which to start copying + * @param len the number of values to copy. + * @return an int[] value + */ + public int[] toArray( int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to + * {@link #getNoEntryValue()}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any "null" elements.) + * + *

NOTE: Trove does not allocate a new array if the array passed in is + * not large enough to hold all of the data elements. It will instead fill + * the array passed in. + * + * @param dest the array to copy into. + * @return the array passed in. + */ + public int[] toArray( int[] dest ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param offset the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public int[] toArray( int[] dest, int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param source_pos the offset of the first value to copy + * @param dest_pos the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public int[] toArray( int[] dest, int source_pos, int dest_pos, int len ); + + + /** + * Applies the procedure to each value in the list in ascending + * (front to back) order. + * + * @param procedure a TIntProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEach( TIntProcedure procedure ); + + + /** + * Applies the procedure to each value in the list in descending + * (back to front) order. + * + * @param procedure a TIntProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEachDescending( TIntProcedure procedure ); + + + /** + * Sort the values in the list (ascending) using the Sun quicksort + * implementation. + * + * @see java.util.Arrays#sort + */ + public void sort(); + + + /** + * Sort a slice of the list (ascending) using the Sun quicksort + * implementation. + * + * @param fromIndex the index at which to start sorting (inclusive) + * @param toIndex the index at which to stop sorting (exclusive) + * @see java.util.Arrays#sort + */ + public void sort( int fromIndex, int toIndex ); + + + /** + * Fills every slot in the list with the specified value. + * + * @param val the value to use when filling + */ + public void fill( int val ); + + + /** + * Fills a range in the list with the specified value. + * + * @param fromIndex the offset at which to start filling (inclusive) + * @param toIndex the offset at which to stop filling (exclusive) + * @param val the value to use when filling + */ + public void fill( int fromIndex, int toIndex, int val ); + + + /** + * Performs a binary search for value in the entire list. + * Note that you must @{link #sort sort} the list before + * doing a search. + * + * @param value the value to search for + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( int value ); + + + /** + * Performs a binary search for value in the specified + * range. Note that you must @{link #sort sort} the list + * or the range before doing a search. + * + * @param value the value to search for + * @param fromIndex the lower boundary of the range (inclusive) + * @param toIndex the upper boundary of the range (exclusive) + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( int value, int fromIndex, int toIndex ); + + + /** + * Searches the list front to back for the index of + * value. + * + * @param value an int value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int value ); + + + /** + * Searches the list front to back for the index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (inclusive) + * @param value an int value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int offset, int value ); + + + /** + * Searches the list back to front for the last index of + * value. + * + * @param value an int value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int value ); + + + /** + * Searches the list back to front for the last index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (exclusive) + * @param value an int value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int offset, int value ); + + + /** + * Searches the list for value + * + * @param value an int value + * @return true if value is in the list. + */ + public boolean contains( int value ); + + + /** + * Searches the list for values satisfying condition in + * the manner of the *nix grep utility. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which match the condition. + */ + public TIntList grep( TIntProcedure condition ); + + + /** + * Searches the list for values which do not satisfy + * condition. This is akin to *nix grep -v. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which do not match the condition. + */ + public TIntList inverseGrep( TIntProcedure condition ); + + + /** + * Finds the maximum value in the list. + * + * @return the largest value in the list. + * @exception IllegalStateException if the list is empty + */ + public int max(); + + + /** + * Finds the minimum value in the list. + * + * @return the smallest value in the list. + * @exception IllegalStateException if the list is empty + */ + public int min(); + + + /** + * Calculates the sum of all the values in the list. + * + * @return the sum of the values in the list (zero if the list is empty). + */ + public int sum(); +} diff --git a/src/gnu/trove/list/TLinkable.java b/src/gnu/trove/list/TLinkable.java new file mode 100644 index 0000000..5223fcc --- /dev/null +++ b/src/gnu/trove/list/TLinkable.java @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +import java.io.Serializable; + + + +/** + * Interface for Objects which can be inserted into a TLinkedList. + * + * @author Eric D. Friedman + * @version $Id: TLinkable.java,v 1.1.2.2 2009/09/04 12:32:33 upholderoftruth Exp $ + * @see gnu.trove.list.linked.TLinkedList + */ + +@SuppressWarnings("rawtypes") +public interface TLinkable extends Serializable { + static final long serialVersionUID = 997545054865482562L; + + /** + * Returns the linked list node after this one. + * + * @return a TLinkable value + */ + public T getNext(); + + + /** + * Returns the linked list node before this one. + * + * @return a TLinkable value + */ + public T getPrevious(); + + + /** + * Sets the linked list node after this one. + * + * @param linkable a TLinkable value + */ + public void setNext( T linkable ); + + + /** + * Sets the linked list node before this one. + * + * @param linkable a TLinkable value + */ + public void setPrevious( T linkable ); +}// TLinkable diff --git a/src/gnu/trove/list/TLinkableAdapter.java b/src/gnu/trove/list/TLinkableAdapter.java new file mode 100644 index 0000000..b313d39 --- /dev/null +++ b/src/gnu/trove/list/TLinkableAdapter.java @@ -0,0 +1,43 @@ +package gnu.trove.list; + +/** + * Simple adapter class implementing {@link TLinkable}, so you don't have to. Example: + *

+	private class MyObject extends TLinkableAdapter {
+		private final String value;
+
+		MyObject( String value ) {
+			this.value = value;
+		}
+		
+		public String getValue() {
+			return value;
+		}
+	}
+ * 
+ */ +@SuppressWarnings({ "rawtypes", "serial" }) +public abstract class TLinkableAdapter implements TLinkable { + private volatile T next; + private volatile T prev; + + @Override + public T getNext() { + return next; + } + + @Override + public void setNext( T next ) { + this.next = next; + } + + @Override + public T getPrevious() { + return prev; + } + + @Override + public void setPrevious( T prev ) { + this.prev = prev; + } +} diff --git a/src/gnu/trove/list/TLongList.java b/src/gnu/trove/list/TLongList.java new file mode 100644 index 0000000..95fb3fc --- /dev/null +++ b/src/gnu/trove/list/TLongList.java @@ -0,0 +1,516 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +import gnu.trove.function.*; +import gnu.trove.procedure.*; +import gnu.trove.TLongCollection; + +import java.io.Serializable; +import java.util.Random; + + + +/** + * Interface for Trove list implementations. + */ +@SuppressWarnings("unused") +public interface TLongList extends TLongCollection { + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue(); + + + /** + * Returns the number of values in the list. + * + * @return the number of values in the list. + */ + public int size(); + + + /** + * Tests whether this list contains any values. + * + * @return true if the list is empty. + */ + public boolean isEmpty(); + + + /** + * Adds val to the end of the list, growing as needed. + * + * @param val an long value + * @return true if the list was modified by the add operation + */ + public boolean add(long val); + + + /** + * Adds the values in the array vals to the end of the + * list, in order. + * + * @param vals an long[] value + */ + public void add( long[] vals ); + + + /** + * Adds a subset of the values in the array vals to the + * end of the list, in order. + * + * @param vals an long[] value + * @param offset the offset at which to start copying + * @param length the number of values to copy. + */ + public void add( long[] vals, int offset, int length ); + + + /** + * Inserts value into the list at offset. All + * values including and to the right of offset are shifted + * to the right. + * + * @param offset an int value + * @param value an long value + */ + public void insert( int offset, long value ); + + + /** + * Inserts the array of values into the list at + * offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an long[] value + */ + public void insert( int offset, long[] values ); + + + /** + * Inserts a slice of the array of values into the list + * at offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an long[] value + * @param valOffset the offset in the values array at which to + * start copying. + * @param len the number of values to copy from the values array + */ + public void insert( int offset, long[] values, int valOffset, int len ); + + + /** + * Returns the value at the specified offset. + * + * @param offset an int value + * @return an long value + */ + public long get( int offset ); + + + /** + * Sets the value at the specified offset. + * + * @param offset an int value + * @param val an long value + * + * @return The value previously at the given index. + */ + public long set( int offset, long val ); + + + /** + * Replace the values in the list starting at offset with + * the contents of the values array. + * + * @param offset the first offset to replace + * @param values the source of the new values + */ + public void set( int offset, long[] values ); + + + /** + * Replace the values in the list starting at offset with + * length values from the values array, starting + * at valOffset. + * + * @param offset the first offset to replace + * @param values the source of the new values + * @param valOffset the first value to copy from the values array + * @param length the number of values to copy + */ + public void set( int offset, long[] values, int valOffset, int length ); + + + /** + * Sets the value at the specified offset and returns the + * previously stored value. + * + * @param offset an int value + * @param val an long value + * @return the value previously stored at offset. + */ + public long replace( int offset, long val ); + + + /** + * Flushes the internal state of the list, resetting the capacity + * to the default. + */ + public void clear(); + + + /** + * Removes value from the list. + * + * @param value an long value + * @return true if the list was modified by the remove operation. + */ + public boolean remove( long value ); + + + /** + * Removes value at a given offset from the list. + * + * @param offset an int value that represents + * the offset to the element to be removed + * @return an long that is the value removed. + */ + public long removeAt( int offset ); + + + /** + * Removes length values from the list, starting at + * offset + * + * @param offset an int value + * @param length an int value + */ + public void remove( int offset, int length ); + + + /** + * Transform each value in the list using the specified function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Reverse the order of the elements in the list. + */ + public void reverse(); + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + public void reverse( int from, int to ); + + + /** + * Shuffle the elements of the list using the specified random + * number generator. + * + * @param rand a Random value + */ + public void shuffle( Random rand ); + + + /** + * Returns a sublist of this list. + * + * @param begin low endpoint (inclusive) of the subList. + * @param end high endpoint (exclusive) of the subList. + * @return sublist of this list from begin, inclusive to end, exclusive. + * @throws IndexOutOfBoundsException - endpoint out of range + * @throws IllegalArgumentException - endpoints out of order (end > begin) + */ + public TLongList subList( int begin, int end ); + + + /** + * Copies the contents of the list into a native array. + * + * @return an long[] value + */ + public long[] toArray(); + + + /** + * Copies a slice of the list into a native array. + * + * @param offset the offset at which to start copying + * @param len the number of values to copy. + * @return an long[] value + */ + public long[] toArray( int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to + * {@link #getNoEntryValue()}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any "null" elements.) + * + *

NOTE: Trove does not allocate a new array if the array passed in is + * not large enough to hold all of the data elements. It will instead fill + * the array passed in. + * + * @param dest the array to copy into. + * @return the array passed in. + */ + public long[] toArray( long[] dest ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param offset the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public long[] toArray( long[] dest, int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param source_pos the offset of the first value to copy + * @param dest_pos the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public long[] toArray( long[] dest, int source_pos, int dest_pos, int len ); + + + /** + * Applies the procedure to each value in the list in ascending + * (front to back) order. + * + * @param procedure a TLongProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEach( TLongProcedure procedure ); + + + /** + * Applies the procedure to each value in the list in descending + * (back to front) order. + * + * @param procedure a TLongProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEachDescending( TLongProcedure procedure ); + + + /** + * Sort the values in the list (ascending) using the Sun quicksort + * implementation. + * + * @see java.util.Arrays#sort + */ + public void sort(); + + + /** + * Sort a slice of the list (ascending) using the Sun quicksort + * implementation. + * + * @param fromIndex the index at which to start sorting (inclusive) + * @param toIndex the index at which to stop sorting (exclusive) + * @see java.util.Arrays#sort + */ + public void sort( int fromIndex, int toIndex ); + + + /** + * Fills every slot in the list with the specified value. + * + * @param val the value to use when filling + */ + public void fill( long val ); + + + /** + * Fills a range in the list with the specified value. + * + * @param fromIndex the offset at which to start filling (inclusive) + * @param toIndex the offset at which to stop filling (exclusive) + * @param val the value to use when filling + */ + public void fill( int fromIndex, int toIndex, long val ); + + + /** + * Performs a binary search for value in the entire list. + * Note that you must @{link #sort sort} the list before + * doing a search. + * + * @param value the value to search for + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( long value ); + + + /** + * Performs a binary search for value in the specified + * range. Note that you must @{link #sort sort} the list + * or the range before doing a search. + * + * @param value the value to search for + * @param fromIndex the lower boundary of the range (inclusive) + * @param toIndex the upper boundary of the range (exclusive) + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( long value, int fromIndex, int toIndex ); + + + /** + * Searches the list front to back for the index of + * value. + * + * @param value an long value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( long value ); + + + /** + * Searches the list front to back for the index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (inclusive) + * @param value an long value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int offset, long value ); + + + /** + * Searches the list back to front for the last index of + * value. + * + * @param value an long value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( long value ); + + + /** + * Searches the list back to front for the last index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (exclusive) + * @param value an long value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int offset, long value ); + + + /** + * Searches the list for value + * + * @param value an long value + * @return true if value is in the list. + */ + public boolean contains( long value ); + + + /** + * Searches the list for values satisfying condition in + * the manner of the *nix grep utility. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which match the condition. + */ + public TLongList grep( TLongProcedure condition ); + + + /** + * Searches the list for values which do not satisfy + * condition. This is akin to *nix grep -v. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which do not match the condition. + */ + public TLongList inverseGrep( TLongProcedure condition ); + + + /** + * Finds the maximum value in the list. + * + * @return the largest value in the list. + * @exception IllegalStateException if the list is empty + */ + public long max(); + + + /** + * Finds the minimum value in the list. + * + * @return the smallest value in the list. + * @exception IllegalStateException if the list is empty + */ + public long min(); + + + /** + * Calculates the sum of all the values in the list. + * + * @return the sum of the values in the list (zero if the list is empty). + */ + public long sum(); +} diff --git a/src/gnu/trove/list/TShortList.java b/src/gnu/trove/list/TShortList.java new file mode 100644 index 0000000..e9ddd3d --- /dev/null +++ b/src/gnu/trove/list/TShortList.java @@ -0,0 +1,516 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +import gnu.trove.function.*; +import gnu.trove.procedure.*; +import gnu.trove.TShortCollection; + +import java.io.Serializable; +import java.util.Random; + + + +/** + * Interface for Trove list implementations. + */ +@SuppressWarnings("unused") +public interface TShortList extends TShortCollection { + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue(); + + + /** + * Returns the number of values in the list. + * + * @return the number of values in the list. + */ + public int size(); + + + /** + * Tests whether this list contains any values. + * + * @return true if the list is empty. + */ + public boolean isEmpty(); + + + /** + * Adds val to the end of the list, growing as needed. + * + * @param val an short value + * @return true if the list was modified by the add operation + */ + public boolean add(short val); + + + /** + * Adds the values in the array vals to the end of the + * list, in order. + * + * @param vals an short[] value + */ + public void add( short[] vals ); + + + /** + * Adds a subset of the values in the array vals to the + * end of the list, in order. + * + * @param vals an short[] value + * @param offset the offset at which to start copying + * @param length the number of values to copy. + */ + public void add( short[] vals, int offset, int length ); + + + /** + * Inserts value into the list at offset. All + * values including and to the right of offset are shifted + * to the right. + * + * @param offset an int value + * @param value an short value + */ + public void insert( int offset, short value ); + + + /** + * Inserts the array of values into the list at + * offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an short[] value + */ + public void insert( int offset, short[] values ); + + + /** + * Inserts a slice of the array of values into the list + * at offset. All values including and to the right of + * offset are shifted to the right. + * + * @param offset an int value + * @param values an short[] value + * @param valOffset the offset in the values array at which to + * start copying. + * @param len the number of values to copy from the values array + */ + public void insert( int offset, short[] values, int valOffset, int len ); + + + /** + * Returns the value at the specified offset. + * + * @param offset an int value + * @return an short value + */ + public short get( int offset ); + + + /** + * Sets the value at the specified offset. + * + * @param offset an int value + * @param val an short value + * + * @return The value previously at the given index. + */ + public short set( int offset, short val ); + + + /** + * Replace the values in the list starting at offset with + * the contents of the values array. + * + * @param offset the first offset to replace + * @param values the source of the new values + */ + public void set( int offset, short[] values ); + + + /** + * Replace the values in the list starting at offset with + * length values from the values array, starting + * at valOffset. + * + * @param offset the first offset to replace + * @param values the source of the new values + * @param valOffset the first value to copy from the values array + * @param length the number of values to copy + */ + public void set( int offset, short[] values, int valOffset, int length ); + + + /** + * Sets the value at the specified offset and returns the + * previously stored value. + * + * @param offset an int value + * @param val an short value + * @return the value previously stored at offset. + */ + public short replace( int offset, short val ); + + + /** + * Flushes the internal state of the list, resetting the capacity + * to the default. + */ + public void clear(); + + + /** + * Removes value from the list. + * + * @param value an short value + * @return true if the list was modified by the remove operation. + */ + public boolean remove( short value ); + + + /** + * Removes value at a given offset from the list. + * + * @param offset an int value that represents + * the offset to the element to be removed + * @return an short that is the value removed. + */ + public short removeAt( int offset ); + + + /** + * Removes length values from the list, starting at + * offset + * + * @param offset an int value + * @param length an int value + */ + public void remove( int offset, int length ); + + + /** + * Transform each value in the list using the specified function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Reverse the order of the elements in the list. + */ + public void reverse(); + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + public void reverse( int from, int to ); + + + /** + * Shuffle the elements of the list using the specified random + * number generator. + * + * @param rand a Random value + */ + public void shuffle( Random rand ); + + + /** + * Returns a sublist of this list. + * + * @param begin low endpoint (inclusive) of the subList. + * @param end high endpoint (exclusive) of the subList. + * @return sublist of this list from begin, inclusive to end, exclusive. + * @throws IndexOutOfBoundsException - endpoint out of range + * @throws IllegalArgumentException - endpoints out of order (end > begin) + */ + public TShortList subList( int begin, int end ); + + + /** + * Copies the contents of the list into a native array. + * + * @return an short[] value + */ + public short[] toArray(); + + + /** + * Copies a slice of the list into a native array. + * + * @param offset the offset at which to start copying + * @param len the number of values to copy. + * @return an short[] value + */ + public short[] toArray( int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + *

If the list fits in the specified array with room to spare (i.e., + * the array has more elements than the list), the element in the array + * immediately following the end of the list is set to + * {@link #getNoEntryValue()}. + * (This is useful in determining the length of the list only if + * the caller knows that the list does not contain any "null" elements.) + * + *

NOTE: Trove does not allocate a new array if the array passed in is + * not large enough to hold all of the data elements. It will instead fill + * the array passed in. + * + * @param dest the array to copy into. + * @return the array passed in. + */ + public short[] toArray( short[] dest ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param offset the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public short[] toArray( short[] dest, int offset, int len ); + + + /** + * Copies a slice of the list into a native array. + * + * @param dest the array to copy into. + * @param source_pos the offset of the first value to copy + * @param dest_pos the offset where the first value should be copied + * @param len the number of values to copy. + * @return the array passed in. + */ + public short[] toArray( short[] dest, int source_pos, int dest_pos, int len ); + + + /** + * Applies the procedure to each value in the list in ascending + * (front to back) order. + * + * @param procedure a TShortProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEach( TShortProcedure procedure ); + + + /** + * Applies the procedure to each value in the list in descending + * (back to front) order. + * + * @param procedure a TShortProcedure value + * @return true if the procedure did not terminate prematurely. + */ + public boolean forEachDescending( TShortProcedure procedure ); + + + /** + * Sort the values in the list (ascending) using the Sun quicksort + * implementation. + * + * @see java.util.Arrays#sort + */ + public void sort(); + + + /** + * Sort a slice of the list (ascending) using the Sun quicksort + * implementation. + * + * @param fromIndex the index at which to start sorting (inclusive) + * @param toIndex the index at which to stop sorting (exclusive) + * @see java.util.Arrays#sort + */ + public void sort( int fromIndex, int toIndex ); + + + /** + * Fills every slot in the list with the specified value. + * + * @param val the value to use when filling + */ + public void fill( short val ); + + + /** + * Fills a range in the list with the specified value. + * + * @param fromIndex the offset at which to start filling (inclusive) + * @param toIndex the offset at which to stop filling (exclusive) + * @param val the value to use when filling + */ + public void fill( int fromIndex, int toIndex, short val ); + + + /** + * Performs a binary search for value in the entire list. + * Note that you must @{link #sort sort} the list before + * doing a search. + * + * @param value the value to search for + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( short value ); + + + /** + * Performs a binary search for value in the specified + * range. Note that you must @{link #sort sort} the list + * or the range before doing a search. + * + * @param value the value to search for + * @param fromIndex the lower boundary of the range (inclusive) + * @param toIndex the upper boundary of the range (exclusive) + * @return the absolute offset in the list of the value, or its + * negative insertion point into the sorted list. + */ + public int binarySearch( short value, int fromIndex, int toIndex ); + + + /** + * Searches the list front to back for the index of + * value. + * + * @param value an short value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( short value ); + + + /** + * Searches the list front to back for the index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (inclusive) + * @param value an short value + * @return the first offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int indexOf( int offset, short value ); + + + /** + * Searches the list back to front for the last index of + * value. + * + * @param value an short value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( short value ); + + + /** + * Searches the list back to front for the last index of + * value, starting at offset. + * + * @param offset the offset at which to start the linear search + * (exclusive) + * @param value an short value + * @return the last offset of the value, or -1 if it is not in + * the list. + * @see #binarySearch for faster searches on sorted lists + */ + public int lastIndexOf( int offset, short value ); + + + /** + * Searches the list for value + * + * @param value an short value + * @return true if value is in the list. + */ + public boolean contains( short value ); + + + /** + * Searches the list for values satisfying condition in + * the manner of the *nix grep utility. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which match the condition. + */ + public TShortList grep( TShortProcedure condition ); + + + /** + * Searches the list for values which do not satisfy + * condition. This is akin to *nix grep -v. + * + * @param condition a condition to apply to each element in the list + * @return a list of values which do not match the condition. + */ + public TShortList inverseGrep( TShortProcedure condition ); + + + /** + * Finds the maximum value in the list. + * + * @return the largest value in the list. + * @exception IllegalStateException if the list is empty + */ + public short max(); + + + /** + * Finds the minimum value in the list. + * + * @return the smallest value in the list. + * @exception IllegalStateException if the list is empty + */ + public short min(); + + + /** + * Calculates the sum of all the values in the list. + * + * @return the sum of the values in the list (zero if the list is empty). + */ + public short sum(); +} diff --git a/src/gnu/trove/list/array/TByteArrayList.java b/src/gnu/trove/list/array/TByteArrayList.java new file mode 100644 index 0000000..34ded51 --- /dev/null +++ b/src/gnu/trove/list/array/TByteArrayList.java @@ -0,0 +1,1087 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.array; + +import gnu.trove.function.TByteFunction; +import gnu.trove.list.TByteList; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.TByteCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, array-backed list of byte primitives. + */ +public class TByteArrayList implements TByteList, Externalizable { + static final long serialVersionUID = 1L; + + /** the data of the list */ + protected byte[] _data; + + /** the index after the last entry in the list */ + protected int _pos; + + /** the default capacity for new lists */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + /** the byte value that represents null */ + protected byte no_entry_value; + + + /** + * Creates a new TByteArrayList instance with the + * default capacity. + */ + @SuppressWarnings({}) + public TByteArrayList() { + this( DEFAULT_CAPACITY, ( byte ) 0 ); + } + + + /** + * Creates a new TByteArrayList instance with the + * specified capacity. + * + * @param capacity an int value + */ + @SuppressWarnings({}) + public TByteArrayList( int capacity ) { + this( capacity, ( byte ) 0 ); + } + + + /** + * Creates a new TByteArrayList instance with the + * specified capacity. + * + * @param capacity an int value + * @param no_entry_value an byte value that represents null. + */ + public TByteArrayList( int capacity, byte no_entry_value ) { + _data = new byte[ capacity ]; + _pos = 0; + this.no_entry_value = no_entry_value; + } + + /** + * Creates a new TByteArrayList instance that contains + * a copy of the collection passed to us. + * + * @param collection the collection to copy + */ + public TByteArrayList ( TByteCollection collection ) { + this( collection.size() ); + addAll( collection ); + } + + + /** + * Creates a new TByteArrayList instance whose + * capacity is the length of values array and whose + * initial contents are the specified values. + *

+ * A defensive copy of the given values is held by the new instance. + * + * @param values an byte[] value + */ + public TByteArrayList( byte[] values ) { + this( values.length ); + add( values ); + } + + protected TByteArrayList(byte[] values, byte no_entry_value, boolean wrap) { + if (!wrap) + throw new IllegalStateException("Wrong call"); + + if (values == null) + throw new IllegalArgumentException("values can not be null"); + + _data = values; + _pos = values.length; + this.no_entry_value = no_entry_value; + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @return + */ + public static TByteArrayList wrap(byte[] values) { + return wrap(values, ( byte ) 0); + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @param no_entry_value + * @return + */ + public static TByteArrayList wrap(byte[] values, byte no_entry_value) { + return new TByteArrayList(values, no_entry_value, true) { + /** + * Growing the wrapped external array is not allow + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) + throw new IllegalStateException("Can not grow ArrayList wrapped external array"); + } + }; + } + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + // sizing + + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + public void ensureCapacity( int capacity ) { + if ( capacity > _data.length ) { + int newCap = Math.max( _data.length << 1, capacity ); + byte[] tmp = new byte[ newCap ]; + System.arraycopy( _data, 0, tmp, 0, _data.length ); + _data = tmp; + } + } + + + /** {@inheritDoc} */ + public int size() { + return _pos; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _pos == 0; + } + + + /** + * Sheds any excess capacity above and beyond the current size of the list. + */ + public void trimToSize() { + if ( _data.length > size() ) { + byte[] tmp = new byte[ size() ]; + toArray( tmp, 0, tmp.length ); + _data = tmp; + } + } + + + // modifying + + /** {@inheritDoc} */ + public boolean add( byte val ) { + ensureCapacity( _pos + 1 ); + _data[ _pos++ ] = val; + return true; + } + + + /** {@inheritDoc} */ + public void add( byte[] vals ) { + add( vals, 0, vals.length ); + } + + + /** {@inheritDoc} */ + public void add( byte[] vals, int offset, int length ) { + ensureCapacity( _pos + length ); + System.arraycopy( vals, offset, _data, _pos, length ); + _pos += length; + } + + + /** {@inheritDoc} */ + public void insert( int offset, byte value ) { + if ( offset == _pos ) { + add( value ); + return; + } + ensureCapacity( _pos + 1 ); + // shift right + System.arraycopy( _data, offset, _data, offset + 1, _pos - offset ); + // insert + _data[ offset ] = value; + _pos++; + } + + + /** {@inheritDoc} */ + public void insert( int offset, byte[] values ) { + insert( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void insert( int offset, byte[] values, int valOffset, int len ) { + if ( offset == _pos ) { + add( values, valOffset, len ); + return; + } + + ensureCapacity( _pos + len ); + // shift right + System.arraycopy( _data, offset, _data, offset + len, _pos - offset ); + // insert + System.arraycopy( values, valOffset, _data, offset, len ); + _pos += len; + } + + + /** {@inheritDoc} */ + public byte get( int offset ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + return _data[ offset ]; + } + + + /** + * Returns the value at the specified offset without doing any bounds checking. + */ + public byte getQuick( int offset ) { + return _data[ offset ]; + } + + + /** {@inheritDoc} */ + public byte set( int offset, byte val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + + byte prev_val = _data[ offset ]; + _data[ offset ] = val; + return prev_val; + } + + + /** {@inheritDoc} */ + public byte replace( int offset, byte val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + byte old = _data[ offset ]; + _data[ offset ] = val; + return old; + } + + + /** {@inheritDoc} */ + public void set( int offset, byte[] values ) { + set( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void set( int offset, byte[] values, int valOffset, int length ) { + if ( offset < 0 || offset + length > _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( values, valOffset, _data, offset, length ); + } + + + /** + * Sets the value at the specified offset without doing any bounds checking. + */ + public void setQuick( int offset, byte val ) { + _data[ offset ] = val; + } + + + /** {@inheritDoc} */ + public void clear() { + clear( DEFAULT_CAPACITY ); + } + + + /** + * Flushes the internal state of the list, setting the capacity of the empty list to + * capacity. + */ + public void clear( int capacity ) { + _data = new byte[ capacity ]; + _pos = 0; + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. + */ + public void reset() { + _pos = 0; + Arrays.fill( _data, no_entry_value ); + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. This method differs from + * {@link #reset()} in that it does not clear the old values in the backing array. + * Thus, it is possible for getQuick to return stale data if this method is used and + * the caller is careless about bounds checking. + */ + public void resetQuick() { + _pos = 0; + } + + + /** {@inheritDoc} */ + public boolean remove( byte value ) { + for ( int index = 0; index < _pos; index++ ) { + if ( value == _data[index] ) { + remove( index, 1 ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public byte removeAt( int offset ) { + byte old = get( offset ); + remove( offset, 1 ); + return old; + } + + + /** {@inheritDoc} */ + public void remove( int offset, int length ) { + if ( length == 0 ) return; + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + if ( offset == 0 ) { + // data at the front + System.arraycopy( _data, length, _data, 0, _pos - length ); + } + else if ( _pos - length == offset ) { + // no copy to make, decrementing pos "deletes" values at + // the end + } + else { + // data in the middle + System.arraycopy( _data, offset + length, _data, offset, + _pos - ( offset + length ) ); + } + _pos -= length; + // no need to clear old values beyond _pos, because this is a + // primitive collection and 0 takes as much room as any other + // value + } + + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteArrayIterator( 0 ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + if ( this == collection ) { + return true; + } + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Byte element : collection ) { + byte e = element.byteValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + boolean changed = false; + for ( byte element : array ) { + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] data = _data; + + for ( int i = _pos; i-- > 0; ) { + if ( Arrays.binarySearch( array, data[i] ) < 0 ) { + remove( i, 1 ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + for ( int i = _pos; i-- > 0; ) { + _data[ i ] = function.execute( _data[ i ] ); + } + } + + + /** {@inheritDoc} */ + public void reverse() { + reverse( 0, _pos ); + } + + + /** {@inheritDoc} */ + public void reverse( int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( i, j ); + } + } + + + /** {@inheritDoc} */ + public void shuffle( Random rand ) { + for ( int i = _pos; i-- > 1; ) { + swap( i, rand.nextInt( i ) ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int i, int j ) { + byte tmp = _data[ i ]; + _data[ i ] = _data[ j ]; + _data[ j ] = tmp; + } + + + // copying + + /** {@inheritDoc} */ + public TByteList subList( int begin, int end ) { + if ( end < begin ) { + throw new IllegalArgumentException( "end index " + end + + " greater than begin index " + begin ); + } + if ( begin < 0 ) { + throw new IndexOutOfBoundsException( "begin index can not be < 0" ); + } + if ( end > _data.length ) { + throw new IndexOutOfBoundsException( "end index < " + _data.length ); + } + TByteArrayList list = new TByteArrayList( end - begin ); + for ( int i = begin; i < end; i++ ) { + list.add( _data[ i ] ); + } + return list; + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return toArray( 0, _pos ); + } + + + /** {@inheritDoc} */ + public byte[] toArray( int offset, int len ) { + byte[] rv = new byte[ len ]; + toArray( rv, offset, len ); + return rv; + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + int len = dest.length; + if ( dest.length > _pos ) { + len = _pos; + dest[len] = no_entry_value; + } + toArray( dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest, int offset, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( _data, offset, dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest, int source_pos, int dest_pos, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( source_pos < 0 || source_pos >= _pos ) { + throw new ArrayIndexOutOfBoundsException( source_pos ); + } + System.arraycopy( _data, source_pos, dest, dest_pos, len ); + return dest; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TByteList ) ) return false; + + if ( other instanceof TByteArrayList ) { + TByteArrayList that = ( TByteArrayList )other; + if ( that.size() != this.size() ) return false; + + for ( int i = _pos; i-- > 0; ) { + if ( this._data[ i ] != that._data[ i ] ) { + return false; + } + } + return true; + } + else { + TByteList that = ( TByteList )other; + if ( that.size() != this.size() ) return false; + + for( int i = 0; i < _pos; i++ ) { + if ( this._data[ i ] != that.get( i ) ) { + return false; + } + } + return true; + } + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = _pos; i-- > 0; ) { + h += HashFunctions.hash( _data[ i ] ); + } + return h; + } + + + // procedures + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + for ( int i = 0; i < _pos; i++ ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachDescending( TByteProcedure procedure ) { + for ( int i = _pos; i-- > 0; ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + // sorting + + /** {@inheritDoc} */ + public void sort() { + Arrays.sort( _data, 0, _pos ); + } + + + /** {@inheritDoc} */ + public void sort( int fromIndex, int toIndex ) { + Arrays.sort( _data, fromIndex, toIndex ); + } + + + // filling + + /** {@inheritDoc} */ + public void fill( byte val ) { + Arrays.fill( _data, 0, _pos, val ); + } + + + /** {@inheritDoc} */ + public void fill( int fromIndex, int toIndex, byte val ) { + if ( toIndex > _pos ) { + ensureCapacity( toIndex ); + _pos = toIndex; + } + Arrays.fill( _data, fromIndex, toIndex, val ); + } + + + // searching + + /** {@inheritDoc} */ + public int binarySearch( byte value ) { + return binarySearch( value, 0, _pos ); + } + + + /** {@inheritDoc} */ + public int binarySearch(byte value, int fromIndex, int toIndex) { + if ( fromIndex < 0 ) { + throw new ArrayIndexOutOfBoundsException( fromIndex ); + } + if ( toIndex > _pos ) { + throw new ArrayIndexOutOfBoundsException( toIndex ); + } + + int low = fromIndex; + int high = toIndex - 1; + + while ( low <= high ) { + int mid = ( low + high ) >>> 1; + byte midVal = _data[ mid ]; + + if ( midVal < value ) { + low = mid + 1; + } + else if ( midVal > value ) { + high = mid - 1; + } + else { + return mid; // value found + } + } + return -( low + 1 ); // value not found. + } + + + /** {@inheritDoc} */ + public int indexOf( byte value ) { + return indexOf( 0, value ); + } + + + /** {@inheritDoc} */ + public int indexOf( int offset, byte value ) { + for ( int i = offset; i < _pos; i++ ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public int lastIndexOf( byte value ) { + return lastIndexOf( _pos, value ); + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int offset, byte value ) { + for ( int i = offset; i-- > 0; ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public boolean contains( byte value ) { + return lastIndexOf( value ) >= 0; + } + + + /** {@inheritDoc} */ + public TByteList grep( TByteProcedure condition ) { + TByteArrayList list = new TByteArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public TByteList inverseGrep( TByteProcedure condition ) { + TByteArrayList list = new TByteArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( !condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public byte max() { + if ( size() == 0 ) { + throw new IllegalStateException("cannot find maximum of an empty list"); + } + byte max = Byte.MIN_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[ i ] > max ) { + max = _data[ i ]; + } + } + return max; + } + + + /** {@inheritDoc} */ + public byte min() { + if ( size() == 0 ) { + throw new IllegalStateException( "cannot find minimum of an empty list" ); + } + byte min = Byte.MAX_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[i] < min ) { + min = _data[i]; + } + } + return min; + } + + + /** {@inheritDoc} */ + public byte sum() { + byte sum = 0; + for ( int i = 0; i < _pos; i++ ) { + sum += _data[ i ]; + } + return sum; + } + + + // stringification + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = 0, end = _pos - 1; i < end; i++ ) { + buf.append( _data[ i ] ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _data[ _pos - 1 ] ); + } + buf.append( "}" ); + return buf.toString(); + } + + + /** TByteArrayList iterator */ + class TByteArrayIterator implements TByteIterator { + + /** Index of element to be returned by subsequent call to next. */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + + TByteArrayIterator( int index ) { + cursor = index; + } + + + /** {@inheritDoc} */ + public boolean hasNext() { + return cursor < size(); + } + + + /** {@inheritDoc} */ + public byte next() { + try { + byte next = get( cursor ); + lastRet = cursor++; + return next; + } catch ( IndexOutOfBoundsException e ) { + throw new NoSuchElementException(); + } + } + + + /** {@inheritDoc} */ + public void remove() { + if ( lastRet == -1 ) + throw new IllegalStateException(); + + try { + TByteArrayList.this.remove( lastRet, 1); + if ( lastRet < cursor ) + cursor--; + lastRet = -1; + } catch ( IndexOutOfBoundsException e ) { + throw new ConcurrentModificationException(); + } + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // POSITION + out.writeInt( _pos ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + + // ENTRIES + int len = _data.length; + out.writeInt( len ); + for( int i = 0; i < len; i++ ) { + out.writeByte( _data[ i ] ); + } + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // POSITION + _pos = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + + // ENTRIES + int len = in.readInt(); + _data = new byte[ len ]; + for( int i = 0; i < len; i++ ) { + _data[ i ] = in.readByte(); + } + } +} // TByteArrayList diff --git a/src/gnu/trove/list/array/TCharArrayList.java b/src/gnu/trove/list/array/TCharArrayList.java new file mode 100644 index 0000000..a014463 --- /dev/null +++ b/src/gnu/trove/list/array/TCharArrayList.java @@ -0,0 +1,1087 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.array; + +import gnu.trove.function.TCharFunction; +import gnu.trove.list.TCharList; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.TCharCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, array-backed list of char primitives. + */ +public class TCharArrayList implements TCharList, Externalizable { + static final long serialVersionUID = 1L; + + /** the data of the list */ + protected char[] _data; + + /** the index after the last entry in the list */ + protected int _pos; + + /** the default capacity for new lists */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + /** the char value that represents null */ + protected char no_entry_value; + + + /** + * Creates a new TCharArrayList instance with the + * default capacity. + */ + @SuppressWarnings({}) + public TCharArrayList() { + this( DEFAULT_CAPACITY, ( char ) 0 ); + } + + + /** + * Creates a new TCharArrayList instance with the + * specified capacity. + * + * @param capacity an int value + */ + @SuppressWarnings({}) + public TCharArrayList( int capacity ) { + this( capacity, ( char ) 0 ); + } + + + /** + * Creates a new TCharArrayList instance with the + * specified capacity. + * + * @param capacity an int value + * @param no_entry_value an char value that represents null. + */ + public TCharArrayList( int capacity, char no_entry_value ) { + _data = new char[ capacity ]; + _pos = 0; + this.no_entry_value = no_entry_value; + } + + /** + * Creates a new TCharArrayList instance that contains + * a copy of the collection passed to us. + * + * @param collection the collection to copy + */ + public TCharArrayList ( TCharCollection collection ) { + this( collection.size() ); + addAll( collection ); + } + + + /** + * Creates a new TCharArrayList instance whose + * capacity is the length of values array and whose + * initial contents are the specified values. + *

+ * A defensive copy of the given values is held by the new instance. + * + * @param values an char[] value + */ + public TCharArrayList( char[] values ) { + this( values.length ); + add( values ); + } + + protected TCharArrayList(char[] values, char no_entry_value, boolean wrap) { + if (!wrap) + throw new IllegalStateException("Wrong call"); + + if (values == null) + throw new IllegalArgumentException("values can not be null"); + + _data = values; + _pos = values.length; + this.no_entry_value = no_entry_value; + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @return + */ + public static TCharArrayList wrap(char[] values) { + return wrap(values, ( char ) 0); + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @param no_entry_value + * @return + */ + public static TCharArrayList wrap(char[] values, char no_entry_value) { + return new TCharArrayList(values, no_entry_value, true) { + /** + * Growing the wrapped external array is not allow + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) + throw new IllegalStateException("Can not grow ArrayList wrapped external array"); + } + }; + } + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + // sizing + + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + public void ensureCapacity( int capacity ) { + if ( capacity > _data.length ) { + int newCap = Math.max( _data.length << 1, capacity ); + char[] tmp = new char[ newCap ]; + System.arraycopy( _data, 0, tmp, 0, _data.length ); + _data = tmp; + } + } + + + /** {@inheritDoc} */ + public int size() { + return _pos; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _pos == 0; + } + + + /** + * Sheds any excess capacity above and beyond the current size of the list. + */ + public void trimToSize() { + if ( _data.length > size() ) { + char[] tmp = new char[ size() ]; + toArray( tmp, 0, tmp.length ); + _data = tmp; + } + } + + + // modifying + + /** {@inheritDoc} */ + public boolean add( char val ) { + ensureCapacity( _pos + 1 ); + _data[ _pos++ ] = val; + return true; + } + + + /** {@inheritDoc} */ + public void add( char[] vals ) { + add( vals, 0, vals.length ); + } + + + /** {@inheritDoc} */ + public void add( char[] vals, int offset, int length ) { + ensureCapacity( _pos + length ); + System.arraycopy( vals, offset, _data, _pos, length ); + _pos += length; + } + + + /** {@inheritDoc} */ + public void insert( int offset, char value ) { + if ( offset == _pos ) { + add( value ); + return; + } + ensureCapacity( _pos + 1 ); + // shift right + System.arraycopy( _data, offset, _data, offset + 1, _pos - offset ); + // insert + _data[ offset ] = value; + _pos++; + } + + + /** {@inheritDoc} */ + public void insert( int offset, char[] values ) { + insert( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void insert( int offset, char[] values, int valOffset, int len ) { + if ( offset == _pos ) { + add( values, valOffset, len ); + return; + } + + ensureCapacity( _pos + len ); + // shift right + System.arraycopy( _data, offset, _data, offset + len, _pos - offset ); + // insert + System.arraycopy( values, valOffset, _data, offset, len ); + _pos += len; + } + + + /** {@inheritDoc} */ + public char get( int offset ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + return _data[ offset ]; + } + + + /** + * Returns the value at the specified offset without doing any bounds checking. + */ + public char getQuick( int offset ) { + return _data[ offset ]; + } + + + /** {@inheritDoc} */ + public char set( int offset, char val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + + char prev_val = _data[ offset ]; + _data[ offset ] = val; + return prev_val; + } + + + /** {@inheritDoc} */ + public char replace( int offset, char val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + char old = _data[ offset ]; + _data[ offset ] = val; + return old; + } + + + /** {@inheritDoc} */ + public void set( int offset, char[] values ) { + set( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void set( int offset, char[] values, int valOffset, int length ) { + if ( offset < 0 || offset + length > _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( values, valOffset, _data, offset, length ); + } + + + /** + * Sets the value at the specified offset without doing any bounds checking. + */ + public void setQuick( int offset, char val ) { + _data[ offset ] = val; + } + + + /** {@inheritDoc} */ + public void clear() { + clear( DEFAULT_CAPACITY ); + } + + + /** + * Flushes the internal state of the list, setting the capacity of the empty list to + * capacity. + */ + public void clear( int capacity ) { + _data = new char[ capacity ]; + _pos = 0; + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. + */ + public void reset() { + _pos = 0; + Arrays.fill( _data, no_entry_value ); + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. This method differs from + * {@link #reset()} in that it does not clear the old values in the backing array. + * Thus, it is possible for getQuick to return stale data if this method is used and + * the caller is careless about bounds checking. + */ + public void resetQuick() { + _pos = 0; + } + + + /** {@inheritDoc} */ + public boolean remove( char value ) { + for ( int index = 0; index < _pos; index++ ) { + if ( value == _data[index] ) { + remove( index, 1 ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public char removeAt( int offset ) { + char old = get( offset ); + remove( offset, 1 ); + return old; + } + + + /** {@inheritDoc} */ + public void remove( int offset, int length ) { + if ( length == 0 ) return; + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + if ( offset == 0 ) { + // data at the front + System.arraycopy( _data, length, _data, 0, _pos - length ); + } + else if ( _pos - length == offset ) { + // no copy to make, decrementing pos "deletes" values at + // the end + } + else { + // data in the middle + System.arraycopy( _data, offset + length, _data, offset, + _pos - ( offset + length ) ); + } + _pos -= length; + // no need to clear old values beyond _pos, because this is a + // primitive collection and 0 takes as much room as any other + // value + } + + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharArrayIterator( 0 ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + if ( this == collection ) { + return true; + } + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Character element : collection ) { + char e = element.charValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + boolean changed = false; + for ( char element : array ) { + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] data = _data; + + for ( int i = _pos; i-- > 0; ) { + if ( Arrays.binarySearch( array, data[i] ) < 0 ) { + remove( i, 1 ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + for ( int i = _pos; i-- > 0; ) { + _data[ i ] = function.execute( _data[ i ] ); + } + } + + + /** {@inheritDoc} */ + public void reverse() { + reverse( 0, _pos ); + } + + + /** {@inheritDoc} */ + public void reverse( int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( i, j ); + } + } + + + /** {@inheritDoc} */ + public void shuffle( Random rand ) { + for ( int i = _pos; i-- > 1; ) { + swap( i, rand.nextInt( i ) ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int i, int j ) { + char tmp = _data[ i ]; + _data[ i ] = _data[ j ]; + _data[ j ] = tmp; + } + + + // copying + + /** {@inheritDoc} */ + public TCharList subList( int begin, int end ) { + if ( end < begin ) { + throw new IllegalArgumentException( "end index " + end + + " greater than begin index " + begin ); + } + if ( begin < 0 ) { + throw new IndexOutOfBoundsException( "begin index can not be < 0" ); + } + if ( end > _data.length ) { + throw new IndexOutOfBoundsException( "end index < " + _data.length ); + } + TCharArrayList list = new TCharArrayList( end - begin ); + for ( int i = begin; i < end; i++ ) { + list.add( _data[ i ] ); + } + return list; + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return toArray( 0, _pos ); + } + + + /** {@inheritDoc} */ + public char[] toArray( int offset, int len ) { + char[] rv = new char[ len ]; + toArray( rv, offset, len ); + return rv; + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + int len = dest.length; + if ( dest.length > _pos ) { + len = _pos; + dest[len] = no_entry_value; + } + toArray( dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest, int offset, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( _data, offset, dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest, int source_pos, int dest_pos, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( source_pos < 0 || source_pos >= _pos ) { + throw new ArrayIndexOutOfBoundsException( source_pos ); + } + System.arraycopy( _data, source_pos, dest, dest_pos, len ); + return dest; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TCharList ) ) return false; + + if ( other instanceof TCharArrayList ) { + TCharArrayList that = ( TCharArrayList )other; + if ( that.size() != this.size() ) return false; + + for ( int i = _pos; i-- > 0; ) { + if ( this._data[ i ] != that._data[ i ] ) { + return false; + } + } + return true; + } + else { + TCharList that = ( TCharList )other; + if ( that.size() != this.size() ) return false; + + for( int i = 0; i < _pos; i++ ) { + if ( this._data[ i ] != that.get( i ) ) { + return false; + } + } + return true; + } + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = _pos; i-- > 0; ) { + h += HashFunctions.hash( _data[ i ] ); + } + return h; + } + + + // procedures + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + for ( int i = 0; i < _pos; i++ ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachDescending( TCharProcedure procedure ) { + for ( int i = _pos; i-- > 0; ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + // sorting + + /** {@inheritDoc} */ + public void sort() { + Arrays.sort( _data, 0, _pos ); + } + + + /** {@inheritDoc} */ + public void sort( int fromIndex, int toIndex ) { + Arrays.sort( _data, fromIndex, toIndex ); + } + + + // filling + + /** {@inheritDoc} */ + public void fill( char val ) { + Arrays.fill( _data, 0, _pos, val ); + } + + + /** {@inheritDoc} */ + public void fill( int fromIndex, int toIndex, char val ) { + if ( toIndex > _pos ) { + ensureCapacity( toIndex ); + _pos = toIndex; + } + Arrays.fill( _data, fromIndex, toIndex, val ); + } + + + // searching + + /** {@inheritDoc} */ + public int binarySearch( char value ) { + return binarySearch( value, 0, _pos ); + } + + + /** {@inheritDoc} */ + public int binarySearch(char value, int fromIndex, int toIndex) { + if ( fromIndex < 0 ) { + throw new ArrayIndexOutOfBoundsException( fromIndex ); + } + if ( toIndex > _pos ) { + throw new ArrayIndexOutOfBoundsException( toIndex ); + } + + int low = fromIndex; + int high = toIndex - 1; + + while ( low <= high ) { + int mid = ( low + high ) >>> 1; + char midVal = _data[ mid ]; + + if ( midVal < value ) { + low = mid + 1; + } + else if ( midVal > value ) { + high = mid - 1; + } + else { + return mid; // value found + } + } + return -( low + 1 ); // value not found. + } + + + /** {@inheritDoc} */ + public int indexOf( char value ) { + return indexOf( 0, value ); + } + + + /** {@inheritDoc} */ + public int indexOf( int offset, char value ) { + for ( int i = offset; i < _pos; i++ ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public int lastIndexOf( char value ) { + return lastIndexOf( _pos, value ); + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int offset, char value ) { + for ( int i = offset; i-- > 0; ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public boolean contains( char value ) { + return lastIndexOf( value ) >= 0; + } + + + /** {@inheritDoc} */ + public TCharList grep( TCharProcedure condition ) { + TCharArrayList list = new TCharArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public TCharList inverseGrep( TCharProcedure condition ) { + TCharArrayList list = new TCharArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( !condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public char max() { + if ( size() == 0 ) { + throw new IllegalStateException("cannot find maximum of an empty list"); + } + char max = Character.MIN_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[ i ] > max ) { + max = _data[ i ]; + } + } + return max; + } + + + /** {@inheritDoc} */ + public char min() { + if ( size() == 0 ) { + throw new IllegalStateException( "cannot find minimum of an empty list" ); + } + char min = Character.MAX_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[i] < min ) { + min = _data[i]; + } + } + return min; + } + + + /** {@inheritDoc} */ + public char sum() { + char sum = 0; + for ( int i = 0; i < _pos; i++ ) { + sum += _data[ i ]; + } + return sum; + } + + + // stringification + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = 0, end = _pos - 1; i < end; i++ ) { + buf.append( _data[ i ] ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _data[ _pos - 1 ] ); + } + buf.append( "}" ); + return buf.toString(); + } + + + /** TCharArrayList iterator */ + class TCharArrayIterator implements TCharIterator { + + /** Index of element to be returned by subsequent call to next. */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + + TCharArrayIterator( int index ) { + cursor = index; + } + + + /** {@inheritDoc} */ + public boolean hasNext() { + return cursor < size(); + } + + + /** {@inheritDoc} */ + public char next() { + try { + char next = get( cursor ); + lastRet = cursor++; + return next; + } catch ( IndexOutOfBoundsException e ) { + throw new NoSuchElementException(); + } + } + + + /** {@inheritDoc} */ + public void remove() { + if ( lastRet == -1 ) + throw new IllegalStateException(); + + try { + TCharArrayList.this.remove( lastRet, 1); + if ( lastRet < cursor ) + cursor--; + lastRet = -1; + } catch ( IndexOutOfBoundsException e ) { + throw new ConcurrentModificationException(); + } + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // POSITION + out.writeInt( _pos ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + + // ENTRIES + int len = _data.length; + out.writeInt( len ); + for( int i = 0; i < len; i++ ) { + out.writeChar( _data[ i ] ); + } + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // POSITION + _pos = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + + // ENTRIES + int len = in.readInt(); + _data = new char[ len ]; + for( int i = 0; i < len; i++ ) { + _data[ i ] = in.readChar(); + } + } +} // TCharArrayList diff --git a/src/gnu/trove/list/array/TDoubleArrayList.java b/src/gnu/trove/list/array/TDoubleArrayList.java new file mode 100644 index 0000000..4a466da --- /dev/null +++ b/src/gnu/trove/list/array/TDoubleArrayList.java @@ -0,0 +1,1087 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.array; + +import gnu.trove.function.TDoubleFunction; +import gnu.trove.list.TDoubleList; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.TDoubleCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, array-backed list of double primitives. + */ +public class TDoubleArrayList implements TDoubleList, Externalizable { + static final long serialVersionUID = 1L; + + /** the data of the list */ + protected double[] _data; + + /** the index after the last entry in the list */ + protected int _pos; + + /** the default capacity for new lists */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + /** the double value that represents null */ + protected double no_entry_value; + + + /** + * Creates a new TDoubleArrayList instance with the + * default capacity. + */ + @SuppressWarnings({}) + public TDoubleArrayList() { + this( DEFAULT_CAPACITY, ( double ) 0 ); + } + + + /** + * Creates a new TDoubleArrayList instance with the + * specified capacity. + * + * @param capacity an int value + */ + @SuppressWarnings({}) + public TDoubleArrayList( int capacity ) { + this( capacity, ( double ) 0 ); + } + + + /** + * Creates a new TDoubleArrayList instance with the + * specified capacity. + * + * @param capacity an int value + * @param no_entry_value an double value that represents null. + */ + public TDoubleArrayList( int capacity, double no_entry_value ) { + _data = new double[ capacity ]; + _pos = 0; + this.no_entry_value = no_entry_value; + } + + /** + * Creates a new TDoubleArrayList instance that contains + * a copy of the collection passed to us. + * + * @param collection the collection to copy + */ + public TDoubleArrayList ( TDoubleCollection collection ) { + this( collection.size() ); + addAll( collection ); + } + + + /** + * Creates a new TDoubleArrayList instance whose + * capacity is the length of values array and whose + * initial contents are the specified values. + *

+ * A defensive copy of the given values is held by the new instance. + * + * @param values an double[] value + */ + public TDoubleArrayList( double[] values ) { + this( values.length ); + add( values ); + } + + protected TDoubleArrayList(double[] values, double no_entry_value, boolean wrap) { + if (!wrap) + throw new IllegalStateException("Wrong call"); + + if (values == null) + throw new IllegalArgumentException("values can not be null"); + + _data = values; + _pos = values.length; + this.no_entry_value = no_entry_value; + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @return + */ + public static TDoubleArrayList wrap(double[] values) { + return wrap(values, ( double ) 0); + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @param no_entry_value + * @return + */ + public static TDoubleArrayList wrap(double[] values, double no_entry_value) { + return new TDoubleArrayList(values, no_entry_value, true) { + /** + * Growing the wrapped external array is not allow + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) + throw new IllegalStateException("Can not grow ArrayList wrapped external array"); + } + }; + } + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + // sizing + + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + public void ensureCapacity( int capacity ) { + if ( capacity > _data.length ) { + int newCap = Math.max( _data.length << 1, capacity ); + double[] tmp = new double[ newCap ]; + System.arraycopy( _data, 0, tmp, 0, _data.length ); + _data = tmp; + } + } + + + /** {@inheritDoc} */ + public int size() { + return _pos; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _pos == 0; + } + + + /** + * Sheds any excess capacity above and beyond the current size of the list. + */ + public void trimToSize() { + if ( _data.length > size() ) { + double[] tmp = new double[ size() ]; + toArray( tmp, 0, tmp.length ); + _data = tmp; + } + } + + + // modifying + + /** {@inheritDoc} */ + public boolean add( double val ) { + ensureCapacity( _pos + 1 ); + _data[ _pos++ ] = val; + return true; + } + + + /** {@inheritDoc} */ + public void add( double[] vals ) { + add( vals, 0, vals.length ); + } + + + /** {@inheritDoc} */ + public void add( double[] vals, int offset, int length ) { + ensureCapacity( _pos + length ); + System.arraycopy( vals, offset, _data, _pos, length ); + _pos += length; + } + + + /** {@inheritDoc} */ + public void insert( int offset, double value ) { + if ( offset == _pos ) { + add( value ); + return; + } + ensureCapacity( _pos + 1 ); + // shift right + System.arraycopy( _data, offset, _data, offset + 1, _pos - offset ); + // insert + _data[ offset ] = value; + _pos++; + } + + + /** {@inheritDoc} */ + public void insert( int offset, double[] values ) { + insert( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void insert( int offset, double[] values, int valOffset, int len ) { + if ( offset == _pos ) { + add( values, valOffset, len ); + return; + } + + ensureCapacity( _pos + len ); + // shift right + System.arraycopy( _data, offset, _data, offset + len, _pos - offset ); + // insert + System.arraycopy( values, valOffset, _data, offset, len ); + _pos += len; + } + + + /** {@inheritDoc} */ + public double get( int offset ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + return _data[ offset ]; + } + + + /** + * Returns the value at the specified offset without doing any bounds checking. + */ + public double getQuick( int offset ) { + return _data[ offset ]; + } + + + /** {@inheritDoc} */ + public double set( int offset, double val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + + double prev_val = _data[ offset ]; + _data[ offset ] = val; + return prev_val; + } + + + /** {@inheritDoc} */ + public double replace( int offset, double val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + double old = _data[ offset ]; + _data[ offset ] = val; + return old; + } + + + /** {@inheritDoc} */ + public void set( int offset, double[] values ) { + set( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void set( int offset, double[] values, int valOffset, int length ) { + if ( offset < 0 || offset + length > _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( values, valOffset, _data, offset, length ); + } + + + /** + * Sets the value at the specified offset without doing any bounds checking. + */ + public void setQuick( int offset, double val ) { + _data[ offset ] = val; + } + + + /** {@inheritDoc} */ + public void clear() { + clear( DEFAULT_CAPACITY ); + } + + + /** + * Flushes the internal state of the list, setting the capacity of the empty list to + * capacity. + */ + public void clear( int capacity ) { + _data = new double[ capacity ]; + _pos = 0; + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. + */ + public void reset() { + _pos = 0; + Arrays.fill( _data, no_entry_value ); + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. This method differs from + * {@link #reset()} in that it does not clear the old values in the backing array. + * Thus, it is possible for getQuick to return stale data if this method is used and + * the caller is careless about bounds checking. + */ + public void resetQuick() { + _pos = 0; + } + + + /** {@inheritDoc} */ + public boolean remove( double value ) { + for ( int index = 0; index < _pos; index++ ) { + if ( value == _data[index] ) { + remove( index, 1 ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public double removeAt( int offset ) { + double old = get( offset ); + remove( offset, 1 ); + return old; + } + + + /** {@inheritDoc} */ + public void remove( int offset, int length ) { + if ( length == 0 ) return; + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + if ( offset == 0 ) { + // data at the front + System.arraycopy( _data, length, _data, 0, _pos - length ); + } + else if ( _pos - length == offset ) { + // no copy to make, decrementing pos "deletes" values at + // the end + } + else { + // data in the middle + System.arraycopy( _data, offset + length, _data, offset, + _pos - ( offset + length ) ); + } + _pos -= length; + // no need to clear old values beyond _pos, because this is a + // primitive collection and 0 takes as much room as any other + // value + } + + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleArrayIterator( 0 ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + if ( this == collection ) { + return true; + } + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Double element : collection ) { + double e = element.doubleValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + boolean changed = false; + for ( double element : array ) { + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] data = _data; + + for ( int i = _pos; i-- > 0; ) { + if ( Arrays.binarySearch( array, data[i] ) < 0 ) { + remove( i, 1 ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + for ( int i = _pos; i-- > 0; ) { + _data[ i ] = function.execute( _data[ i ] ); + } + } + + + /** {@inheritDoc} */ + public void reverse() { + reverse( 0, _pos ); + } + + + /** {@inheritDoc} */ + public void reverse( int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( i, j ); + } + } + + + /** {@inheritDoc} */ + public void shuffle( Random rand ) { + for ( int i = _pos; i-- > 1; ) { + swap( i, rand.nextInt( i ) ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int i, int j ) { + double tmp = _data[ i ]; + _data[ i ] = _data[ j ]; + _data[ j ] = tmp; + } + + + // copying + + /** {@inheritDoc} */ + public TDoubleList subList( int begin, int end ) { + if ( end < begin ) { + throw new IllegalArgumentException( "end index " + end + + " greater than begin index " + begin ); + } + if ( begin < 0 ) { + throw new IndexOutOfBoundsException( "begin index can not be < 0" ); + } + if ( end > _data.length ) { + throw new IndexOutOfBoundsException( "end index < " + _data.length ); + } + TDoubleArrayList list = new TDoubleArrayList( end - begin ); + for ( int i = begin; i < end; i++ ) { + list.add( _data[ i ] ); + } + return list; + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return toArray( 0, _pos ); + } + + + /** {@inheritDoc} */ + public double[] toArray( int offset, int len ) { + double[] rv = new double[ len ]; + toArray( rv, offset, len ); + return rv; + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + int len = dest.length; + if ( dest.length > _pos ) { + len = _pos; + dest[len] = no_entry_value; + } + toArray( dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest, int offset, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( _data, offset, dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest, int source_pos, int dest_pos, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( source_pos < 0 || source_pos >= _pos ) { + throw new ArrayIndexOutOfBoundsException( source_pos ); + } + System.arraycopy( _data, source_pos, dest, dest_pos, len ); + return dest; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TDoubleList ) ) return false; + + if ( other instanceof TDoubleArrayList ) { + TDoubleArrayList that = ( TDoubleArrayList )other; + if ( that.size() != this.size() ) return false; + + for ( int i = _pos; i-- > 0; ) { + if ( this._data[ i ] != that._data[ i ] ) { + return false; + } + } + return true; + } + else { + TDoubleList that = ( TDoubleList )other; + if ( that.size() != this.size() ) return false; + + for( int i = 0; i < _pos; i++ ) { + if ( this._data[ i ] != that.get( i ) ) { + return false; + } + } + return true; + } + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = _pos; i-- > 0; ) { + h += HashFunctions.hash( _data[ i ] ); + } + return h; + } + + + // procedures + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + for ( int i = 0; i < _pos; i++ ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachDescending( TDoubleProcedure procedure ) { + for ( int i = _pos; i-- > 0; ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + // sorting + + /** {@inheritDoc} */ + public void sort() { + Arrays.sort( _data, 0, _pos ); + } + + + /** {@inheritDoc} */ + public void sort( int fromIndex, int toIndex ) { + Arrays.sort( _data, fromIndex, toIndex ); + } + + + // filling + + /** {@inheritDoc} */ + public void fill( double val ) { + Arrays.fill( _data, 0, _pos, val ); + } + + + /** {@inheritDoc} */ + public void fill( int fromIndex, int toIndex, double val ) { + if ( toIndex > _pos ) { + ensureCapacity( toIndex ); + _pos = toIndex; + } + Arrays.fill( _data, fromIndex, toIndex, val ); + } + + + // searching + + /** {@inheritDoc} */ + public int binarySearch( double value ) { + return binarySearch( value, 0, _pos ); + } + + + /** {@inheritDoc} */ + public int binarySearch(double value, int fromIndex, int toIndex) { + if ( fromIndex < 0 ) { + throw new ArrayIndexOutOfBoundsException( fromIndex ); + } + if ( toIndex > _pos ) { + throw new ArrayIndexOutOfBoundsException( toIndex ); + } + + int low = fromIndex; + int high = toIndex - 1; + + while ( low <= high ) { + int mid = ( low + high ) >>> 1; + double midVal = _data[ mid ]; + + if ( midVal < value ) { + low = mid + 1; + } + else if ( midVal > value ) { + high = mid - 1; + } + else { + return mid; // value found + } + } + return -( low + 1 ); // value not found. + } + + + /** {@inheritDoc} */ + public int indexOf( double value ) { + return indexOf( 0, value ); + } + + + /** {@inheritDoc} */ + public int indexOf( int offset, double value ) { + for ( int i = offset; i < _pos; i++ ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public int lastIndexOf( double value ) { + return lastIndexOf( _pos, value ); + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int offset, double value ) { + for ( int i = offset; i-- > 0; ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public boolean contains( double value ) { + return lastIndexOf( value ) >= 0; + } + + + /** {@inheritDoc} */ + public TDoubleList grep( TDoubleProcedure condition ) { + TDoubleArrayList list = new TDoubleArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public TDoubleList inverseGrep( TDoubleProcedure condition ) { + TDoubleArrayList list = new TDoubleArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( !condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public double max() { + if ( size() == 0 ) { + throw new IllegalStateException("cannot find maximum of an empty list"); + } + double max = Double.NEGATIVE_INFINITY; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[ i ] > max ) { + max = _data[ i ]; + } + } + return max; + } + + + /** {@inheritDoc} */ + public double min() { + if ( size() == 0 ) { + throw new IllegalStateException( "cannot find minimum of an empty list" ); + } + double min = Double.POSITIVE_INFINITY; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[i] < min ) { + min = _data[i]; + } + } + return min; + } + + + /** {@inheritDoc} */ + public double sum() { + double sum = 0; + for ( int i = 0; i < _pos; i++ ) { + sum += _data[ i ]; + } + return sum; + } + + + // stringification + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = 0, end = _pos - 1; i < end; i++ ) { + buf.append( _data[ i ] ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _data[ _pos - 1 ] ); + } + buf.append( "}" ); + return buf.toString(); + } + + + /** TDoubleArrayList iterator */ + class TDoubleArrayIterator implements TDoubleIterator { + + /** Index of element to be returned by subsequent call to next. */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + + TDoubleArrayIterator( int index ) { + cursor = index; + } + + + /** {@inheritDoc} */ + public boolean hasNext() { + return cursor < size(); + } + + + /** {@inheritDoc} */ + public double next() { + try { + double next = get( cursor ); + lastRet = cursor++; + return next; + } catch ( IndexOutOfBoundsException e ) { + throw new NoSuchElementException(); + } + } + + + /** {@inheritDoc} */ + public void remove() { + if ( lastRet == -1 ) + throw new IllegalStateException(); + + try { + TDoubleArrayList.this.remove( lastRet, 1); + if ( lastRet < cursor ) + cursor--; + lastRet = -1; + } catch ( IndexOutOfBoundsException e ) { + throw new ConcurrentModificationException(); + } + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // POSITION + out.writeInt( _pos ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + + // ENTRIES + int len = _data.length; + out.writeInt( len ); + for( int i = 0; i < len; i++ ) { + out.writeDouble( _data[ i ] ); + } + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // POSITION + _pos = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + + // ENTRIES + int len = in.readInt(); + _data = new double[ len ]; + for( int i = 0; i < len; i++ ) { + _data[ i ] = in.readDouble(); + } + } +} // TDoubleArrayList diff --git a/src/gnu/trove/list/array/TFloatArrayList.java b/src/gnu/trove/list/array/TFloatArrayList.java new file mode 100644 index 0000000..720958c --- /dev/null +++ b/src/gnu/trove/list/array/TFloatArrayList.java @@ -0,0 +1,1087 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.array; + +import gnu.trove.function.TFloatFunction; +import gnu.trove.list.TFloatList; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.TFloatCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, array-backed list of float primitives. + */ +public class TFloatArrayList implements TFloatList, Externalizable { + static final long serialVersionUID = 1L; + + /** the data of the list */ + protected float[] _data; + + /** the index after the last entry in the list */ + protected int _pos; + + /** the default capacity for new lists */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + /** the float value that represents null */ + protected float no_entry_value; + + + /** + * Creates a new TFloatArrayList instance with the + * default capacity. + */ + @SuppressWarnings({}) + public TFloatArrayList() { + this( DEFAULT_CAPACITY, ( float ) 0 ); + } + + + /** + * Creates a new TFloatArrayList instance with the + * specified capacity. + * + * @param capacity an int value + */ + @SuppressWarnings({}) + public TFloatArrayList( int capacity ) { + this( capacity, ( float ) 0 ); + } + + + /** + * Creates a new TFloatArrayList instance with the + * specified capacity. + * + * @param capacity an int value + * @param no_entry_value an float value that represents null. + */ + public TFloatArrayList( int capacity, float no_entry_value ) { + _data = new float[ capacity ]; + _pos = 0; + this.no_entry_value = no_entry_value; + } + + /** + * Creates a new TFloatArrayList instance that contains + * a copy of the collection passed to us. + * + * @param collection the collection to copy + */ + public TFloatArrayList ( TFloatCollection collection ) { + this( collection.size() ); + addAll( collection ); + } + + + /** + * Creates a new TFloatArrayList instance whose + * capacity is the length of values array and whose + * initial contents are the specified values. + *

+ * A defensive copy of the given values is held by the new instance. + * + * @param values an float[] value + */ + public TFloatArrayList( float[] values ) { + this( values.length ); + add( values ); + } + + protected TFloatArrayList(float[] values, float no_entry_value, boolean wrap) { + if (!wrap) + throw new IllegalStateException("Wrong call"); + + if (values == null) + throw new IllegalArgumentException("values can not be null"); + + _data = values; + _pos = values.length; + this.no_entry_value = no_entry_value; + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @return + */ + public static TFloatArrayList wrap(float[] values) { + return wrap(values, ( float ) 0); + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @param no_entry_value + * @return + */ + public static TFloatArrayList wrap(float[] values, float no_entry_value) { + return new TFloatArrayList(values, no_entry_value, true) { + /** + * Growing the wrapped external array is not allow + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) + throw new IllegalStateException("Can not grow ArrayList wrapped external array"); + } + }; + } + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + // sizing + + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + public void ensureCapacity( int capacity ) { + if ( capacity > _data.length ) { + int newCap = Math.max( _data.length << 1, capacity ); + float[] tmp = new float[ newCap ]; + System.arraycopy( _data, 0, tmp, 0, _data.length ); + _data = tmp; + } + } + + + /** {@inheritDoc} */ + public int size() { + return _pos; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _pos == 0; + } + + + /** + * Sheds any excess capacity above and beyond the current size of the list. + */ + public void trimToSize() { + if ( _data.length > size() ) { + float[] tmp = new float[ size() ]; + toArray( tmp, 0, tmp.length ); + _data = tmp; + } + } + + + // modifying + + /** {@inheritDoc} */ + public boolean add( float val ) { + ensureCapacity( _pos + 1 ); + _data[ _pos++ ] = val; + return true; + } + + + /** {@inheritDoc} */ + public void add( float[] vals ) { + add( vals, 0, vals.length ); + } + + + /** {@inheritDoc} */ + public void add( float[] vals, int offset, int length ) { + ensureCapacity( _pos + length ); + System.arraycopy( vals, offset, _data, _pos, length ); + _pos += length; + } + + + /** {@inheritDoc} */ + public void insert( int offset, float value ) { + if ( offset == _pos ) { + add( value ); + return; + } + ensureCapacity( _pos + 1 ); + // shift right + System.arraycopy( _data, offset, _data, offset + 1, _pos - offset ); + // insert + _data[ offset ] = value; + _pos++; + } + + + /** {@inheritDoc} */ + public void insert( int offset, float[] values ) { + insert( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void insert( int offset, float[] values, int valOffset, int len ) { + if ( offset == _pos ) { + add( values, valOffset, len ); + return; + } + + ensureCapacity( _pos + len ); + // shift right + System.arraycopy( _data, offset, _data, offset + len, _pos - offset ); + // insert + System.arraycopy( values, valOffset, _data, offset, len ); + _pos += len; + } + + + /** {@inheritDoc} */ + public float get( int offset ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + return _data[ offset ]; + } + + + /** + * Returns the value at the specified offset without doing any bounds checking. + */ + public float getQuick( int offset ) { + return _data[ offset ]; + } + + + /** {@inheritDoc} */ + public float set( int offset, float val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + + float prev_val = _data[ offset ]; + _data[ offset ] = val; + return prev_val; + } + + + /** {@inheritDoc} */ + public float replace( int offset, float val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + float old = _data[ offset ]; + _data[ offset ] = val; + return old; + } + + + /** {@inheritDoc} */ + public void set( int offset, float[] values ) { + set( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void set( int offset, float[] values, int valOffset, int length ) { + if ( offset < 0 || offset + length > _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( values, valOffset, _data, offset, length ); + } + + + /** + * Sets the value at the specified offset without doing any bounds checking. + */ + public void setQuick( int offset, float val ) { + _data[ offset ] = val; + } + + + /** {@inheritDoc} */ + public void clear() { + clear( DEFAULT_CAPACITY ); + } + + + /** + * Flushes the internal state of the list, setting the capacity of the empty list to + * capacity. + */ + public void clear( int capacity ) { + _data = new float[ capacity ]; + _pos = 0; + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. + */ + public void reset() { + _pos = 0; + Arrays.fill( _data, no_entry_value ); + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. This method differs from + * {@link #reset()} in that it does not clear the old values in the backing array. + * Thus, it is possible for getQuick to return stale data if this method is used and + * the caller is careless about bounds checking. + */ + public void resetQuick() { + _pos = 0; + } + + + /** {@inheritDoc} */ + public boolean remove( float value ) { + for ( int index = 0; index < _pos; index++ ) { + if ( value == _data[index] ) { + remove( index, 1 ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public float removeAt( int offset ) { + float old = get( offset ); + remove( offset, 1 ); + return old; + } + + + /** {@inheritDoc} */ + public void remove( int offset, int length ) { + if ( length == 0 ) return; + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + if ( offset == 0 ) { + // data at the front + System.arraycopy( _data, length, _data, 0, _pos - length ); + } + else if ( _pos - length == offset ) { + // no copy to make, decrementing pos "deletes" values at + // the end + } + else { + // data in the middle + System.arraycopy( _data, offset + length, _data, offset, + _pos - ( offset + length ) ); + } + _pos -= length; + // no need to clear old values beyond _pos, because this is a + // primitive collection and 0 takes as much room as any other + // value + } + + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatArrayIterator( 0 ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + if ( this == collection ) { + return true; + } + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Float element : collection ) { + float e = element.floatValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + boolean changed = false; + for ( float element : array ) { + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] data = _data; + + for ( int i = _pos; i-- > 0; ) { + if ( Arrays.binarySearch( array, data[i] ) < 0 ) { + remove( i, 1 ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + for ( int i = _pos; i-- > 0; ) { + _data[ i ] = function.execute( _data[ i ] ); + } + } + + + /** {@inheritDoc} */ + public void reverse() { + reverse( 0, _pos ); + } + + + /** {@inheritDoc} */ + public void reverse( int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( i, j ); + } + } + + + /** {@inheritDoc} */ + public void shuffle( Random rand ) { + for ( int i = _pos; i-- > 1; ) { + swap( i, rand.nextInt( i ) ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int i, int j ) { + float tmp = _data[ i ]; + _data[ i ] = _data[ j ]; + _data[ j ] = tmp; + } + + + // copying + + /** {@inheritDoc} */ + public TFloatList subList( int begin, int end ) { + if ( end < begin ) { + throw new IllegalArgumentException( "end index " + end + + " greater than begin index " + begin ); + } + if ( begin < 0 ) { + throw new IndexOutOfBoundsException( "begin index can not be < 0" ); + } + if ( end > _data.length ) { + throw new IndexOutOfBoundsException( "end index < " + _data.length ); + } + TFloatArrayList list = new TFloatArrayList( end - begin ); + for ( int i = begin; i < end; i++ ) { + list.add( _data[ i ] ); + } + return list; + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return toArray( 0, _pos ); + } + + + /** {@inheritDoc} */ + public float[] toArray( int offset, int len ) { + float[] rv = new float[ len ]; + toArray( rv, offset, len ); + return rv; + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + int len = dest.length; + if ( dest.length > _pos ) { + len = _pos; + dest[len] = no_entry_value; + } + toArray( dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest, int offset, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( _data, offset, dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest, int source_pos, int dest_pos, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( source_pos < 0 || source_pos >= _pos ) { + throw new ArrayIndexOutOfBoundsException( source_pos ); + } + System.arraycopy( _data, source_pos, dest, dest_pos, len ); + return dest; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TFloatList ) ) return false; + + if ( other instanceof TFloatArrayList ) { + TFloatArrayList that = ( TFloatArrayList )other; + if ( that.size() != this.size() ) return false; + + for ( int i = _pos; i-- > 0; ) { + if ( this._data[ i ] != that._data[ i ] ) { + return false; + } + } + return true; + } + else { + TFloatList that = ( TFloatList )other; + if ( that.size() != this.size() ) return false; + + for( int i = 0; i < _pos; i++ ) { + if ( this._data[ i ] != that.get( i ) ) { + return false; + } + } + return true; + } + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = _pos; i-- > 0; ) { + h += HashFunctions.hash( _data[ i ] ); + } + return h; + } + + + // procedures + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + for ( int i = 0; i < _pos; i++ ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachDescending( TFloatProcedure procedure ) { + for ( int i = _pos; i-- > 0; ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + // sorting + + /** {@inheritDoc} */ + public void sort() { + Arrays.sort( _data, 0, _pos ); + } + + + /** {@inheritDoc} */ + public void sort( int fromIndex, int toIndex ) { + Arrays.sort( _data, fromIndex, toIndex ); + } + + + // filling + + /** {@inheritDoc} */ + public void fill( float val ) { + Arrays.fill( _data, 0, _pos, val ); + } + + + /** {@inheritDoc} */ + public void fill( int fromIndex, int toIndex, float val ) { + if ( toIndex > _pos ) { + ensureCapacity( toIndex ); + _pos = toIndex; + } + Arrays.fill( _data, fromIndex, toIndex, val ); + } + + + // searching + + /** {@inheritDoc} */ + public int binarySearch( float value ) { + return binarySearch( value, 0, _pos ); + } + + + /** {@inheritDoc} */ + public int binarySearch(float value, int fromIndex, int toIndex) { + if ( fromIndex < 0 ) { + throw new ArrayIndexOutOfBoundsException( fromIndex ); + } + if ( toIndex > _pos ) { + throw new ArrayIndexOutOfBoundsException( toIndex ); + } + + int low = fromIndex; + int high = toIndex - 1; + + while ( low <= high ) { + int mid = ( low + high ) >>> 1; + float midVal = _data[ mid ]; + + if ( midVal < value ) { + low = mid + 1; + } + else if ( midVal > value ) { + high = mid - 1; + } + else { + return mid; // value found + } + } + return -( low + 1 ); // value not found. + } + + + /** {@inheritDoc} */ + public int indexOf( float value ) { + return indexOf( 0, value ); + } + + + /** {@inheritDoc} */ + public int indexOf( int offset, float value ) { + for ( int i = offset; i < _pos; i++ ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public int lastIndexOf( float value ) { + return lastIndexOf( _pos, value ); + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int offset, float value ) { + for ( int i = offset; i-- > 0; ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public boolean contains( float value ) { + return lastIndexOf( value ) >= 0; + } + + + /** {@inheritDoc} */ + public TFloatList grep( TFloatProcedure condition ) { + TFloatArrayList list = new TFloatArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public TFloatList inverseGrep( TFloatProcedure condition ) { + TFloatArrayList list = new TFloatArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( !condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public float max() { + if ( size() == 0 ) { + throw new IllegalStateException("cannot find maximum of an empty list"); + } + float max = Float.NEGATIVE_INFINITY; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[ i ] > max ) { + max = _data[ i ]; + } + } + return max; + } + + + /** {@inheritDoc} */ + public float min() { + if ( size() == 0 ) { + throw new IllegalStateException( "cannot find minimum of an empty list" ); + } + float min = Float.POSITIVE_INFINITY; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[i] < min ) { + min = _data[i]; + } + } + return min; + } + + + /** {@inheritDoc} */ + public float sum() { + float sum = 0; + for ( int i = 0; i < _pos; i++ ) { + sum += _data[ i ]; + } + return sum; + } + + + // stringification + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = 0, end = _pos - 1; i < end; i++ ) { + buf.append( _data[ i ] ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _data[ _pos - 1 ] ); + } + buf.append( "}" ); + return buf.toString(); + } + + + /** TFloatArrayList iterator */ + class TFloatArrayIterator implements TFloatIterator { + + /** Index of element to be returned by subsequent call to next. */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + + TFloatArrayIterator( int index ) { + cursor = index; + } + + + /** {@inheritDoc} */ + public boolean hasNext() { + return cursor < size(); + } + + + /** {@inheritDoc} */ + public float next() { + try { + float next = get( cursor ); + lastRet = cursor++; + return next; + } catch ( IndexOutOfBoundsException e ) { + throw new NoSuchElementException(); + } + } + + + /** {@inheritDoc} */ + public void remove() { + if ( lastRet == -1 ) + throw new IllegalStateException(); + + try { + TFloatArrayList.this.remove( lastRet, 1); + if ( lastRet < cursor ) + cursor--; + lastRet = -1; + } catch ( IndexOutOfBoundsException e ) { + throw new ConcurrentModificationException(); + } + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // POSITION + out.writeInt( _pos ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + + // ENTRIES + int len = _data.length; + out.writeInt( len ); + for( int i = 0; i < len; i++ ) { + out.writeFloat( _data[ i ] ); + } + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // POSITION + _pos = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + + // ENTRIES + int len = in.readInt(); + _data = new float[ len ]; + for( int i = 0; i < len; i++ ) { + _data[ i ] = in.readFloat(); + } + } +} // TFloatArrayList diff --git a/src/gnu/trove/list/array/TIntArrayList.java b/src/gnu/trove/list/array/TIntArrayList.java new file mode 100644 index 0000000..7061372 --- /dev/null +++ b/src/gnu/trove/list/array/TIntArrayList.java @@ -0,0 +1,1087 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.array; + +import gnu.trove.function.TIntFunction; +import gnu.trove.list.TIntList; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.TIntCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, array-backed list of int primitives. + */ +public class TIntArrayList implements TIntList, Externalizable { + static final long serialVersionUID = 1L; + + /** the data of the list */ + protected int[] _data; + + /** the index after the last entry in the list */ + protected int _pos; + + /** the default capacity for new lists */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + /** the int value that represents null */ + protected int no_entry_value; + + + /** + * Creates a new TIntArrayList instance with the + * default capacity. + */ + @SuppressWarnings({}) + public TIntArrayList() { + this( DEFAULT_CAPACITY, ( int ) 0 ); + } + + + /** + * Creates a new TIntArrayList instance with the + * specified capacity. + * + * @param capacity an int value + */ + @SuppressWarnings({}) + public TIntArrayList( int capacity ) { + this( capacity, ( int ) 0 ); + } + + + /** + * Creates a new TIntArrayList instance with the + * specified capacity. + * + * @param capacity an int value + * @param no_entry_value an int value that represents null. + */ + public TIntArrayList( int capacity, int no_entry_value ) { + _data = new int[ capacity ]; + _pos = 0; + this.no_entry_value = no_entry_value; + } + + /** + * Creates a new TIntArrayList instance that contains + * a copy of the collection passed to us. + * + * @param collection the collection to copy + */ + public TIntArrayList ( TIntCollection collection ) { + this( collection.size() ); + addAll( collection ); + } + + + /** + * Creates a new TIntArrayList instance whose + * capacity is the length of values array and whose + * initial contents are the specified values. + *

+ * A defensive copy of the given values is held by the new instance. + * + * @param values an int[] value + */ + public TIntArrayList( int[] values ) { + this( values.length ); + add( values ); + } + + protected TIntArrayList(int[] values, int no_entry_value, boolean wrap) { + if (!wrap) + throw new IllegalStateException("Wrong call"); + + if (values == null) + throw new IllegalArgumentException("values can not be null"); + + _data = values; + _pos = values.length; + this.no_entry_value = no_entry_value; + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @return + */ + public static TIntArrayList wrap(int[] values) { + return wrap(values, ( int ) 0); + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @param no_entry_value + * @return + */ + public static TIntArrayList wrap(int[] values, int no_entry_value) { + return new TIntArrayList(values, no_entry_value, true) { + /** + * Growing the wrapped external array is not allow + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) + throw new IllegalStateException("Can not grow ArrayList wrapped external array"); + } + }; + } + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + // sizing + + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + public void ensureCapacity( int capacity ) { + if ( capacity > _data.length ) { + int newCap = Math.max( _data.length << 1, capacity ); + int[] tmp = new int[ newCap ]; + System.arraycopy( _data, 0, tmp, 0, _data.length ); + _data = tmp; + } + } + + + /** {@inheritDoc} */ + public int size() { + return _pos; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _pos == 0; + } + + + /** + * Sheds any excess capacity above and beyond the current size of the list. + */ + public void trimToSize() { + if ( _data.length > size() ) { + int[] tmp = new int[ size() ]; + toArray( tmp, 0, tmp.length ); + _data = tmp; + } + } + + + // modifying + + /** {@inheritDoc} */ + public boolean add( int val ) { + ensureCapacity( _pos + 1 ); + _data[ _pos++ ] = val; + return true; + } + + + /** {@inheritDoc} */ + public void add( int[] vals ) { + add( vals, 0, vals.length ); + } + + + /** {@inheritDoc} */ + public void add( int[] vals, int offset, int length ) { + ensureCapacity( _pos + length ); + System.arraycopy( vals, offset, _data, _pos, length ); + _pos += length; + } + + + /** {@inheritDoc} */ + public void insert( int offset, int value ) { + if ( offset == _pos ) { + add( value ); + return; + } + ensureCapacity( _pos + 1 ); + // shift right + System.arraycopy( _data, offset, _data, offset + 1, _pos - offset ); + // insert + _data[ offset ] = value; + _pos++; + } + + + /** {@inheritDoc} */ + public void insert( int offset, int[] values ) { + insert( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void insert( int offset, int[] values, int valOffset, int len ) { + if ( offset == _pos ) { + add( values, valOffset, len ); + return; + } + + ensureCapacity( _pos + len ); + // shift right + System.arraycopy( _data, offset, _data, offset + len, _pos - offset ); + // insert + System.arraycopy( values, valOffset, _data, offset, len ); + _pos += len; + } + + + /** {@inheritDoc} */ + public int get( int offset ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + return _data[ offset ]; + } + + + /** + * Returns the value at the specified offset without doing any bounds checking. + */ + public int getQuick( int offset ) { + return _data[ offset ]; + } + + + /** {@inheritDoc} */ + public int set( int offset, int val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + + int prev_val = _data[ offset ]; + _data[ offset ] = val; + return prev_val; + } + + + /** {@inheritDoc} */ + public int replace( int offset, int val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + int old = _data[ offset ]; + _data[ offset ] = val; + return old; + } + + + /** {@inheritDoc} */ + public void set( int offset, int[] values ) { + set( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void set( int offset, int[] values, int valOffset, int length ) { + if ( offset < 0 || offset + length > _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( values, valOffset, _data, offset, length ); + } + + + /** + * Sets the value at the specified offset without doing any bounds checking. + */ + public void setQuick( int offset, int val ) { + _data[ offset ] = val; + } + + + /** {@inheritDoc} */ + public void clear() { + clear( DEFAULT_CAPACITY ); + } + + + /** + * Flushes the internal state of the list, setting the capacity of the empty list to + * capacity. + */ + public void clear( int capacity ) { + _data = new int[ capacity ]; + _pos = 0; + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. + */ + public void reset() { + _pos = 0; + Arrays.fill( _data, no_entry_value ); + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. This method differs from + * {@link #reset()} in that it does not clear the old values in the backing array. + * Thus, it is possible for getQuick to return stale data if this method is used and + * the caller is careless about bounds checking. + */ + public void resetQuick() { + _pos = 0; + } + + + /** {@inheritDoc} */ + public boolean remove( int value ) { + for ( int index = 0; index < _pos; index++ ) { + if ( value == _data[index] ) { + remove( index, 1 ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public int removeAt( int offset ) { + int old = get( offset ); + remove( offset, 1 ); + return old; + } + + + /** {@inheritDoc} */ + public void remove( int offset, int length ) { + if ( length == 0 ) return; + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + if ( offset == 0 ) { + // data at the front + System.arraycopy( _data, length, _data, 0, _pos - length ); + } + else if ( _pos - length == offset ) { + // no copy to make, decrementing pos "deletes" values at + // the end + } + else { + // data in the middle + System.arraycopy( _data, offset + length, _data, offset, + _pos - ( offset + length ) ); + } + _pos -= length; + // no need to clear old values beyond _pos, because this is a + // primitive collection and 0 takes as much room as any other + // value + } + + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntArrayIterator( 0 ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + if ( this == collection ) { + return true; + } + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Integer element : collection ) { + int e = element.intValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + boolean changed = false; + for ( int element : array ) { + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] data = _data; + + for ( int i = _pos; i-- > 0; ) { + if ( Arrays.binarySearch( array, data[i] ) < 0 ) { + remove( i, 1 ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + for ( int i = _pos; i-- > 0; ) { + _data[ i ] = function.execute( _data[ i ] ); + } + } + + + /** {@inheritDoc} */ + public void reverse() { + reverse( 0, _pos ); + } + + + /** {@inheritDoc} */ + public void reverse( int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( i, j ); + } + } + + + /** {@inheritDoc} */ + public void shuffle( Random rand ) { + for ( int i = _pos; i-- > 1; ) { + swap( i, rand.nextInt( i ) ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int i, int j ) { + int tmp = _data[ i ]; + _data[ i ] = _data[ j ]; + _data[ j ] = tmp; + } + + + // copying + + /** {@inheritDoc} */ + public TIntList subList( int begin, int end ) { + if ( end < begin ) { + throw new IllegalArgumentException( "end index " + end + + " greater than begin index " + begin ); + } + if ( begin < 0 ) { + throw new IndexOutOfBoundsException( "begin index can not be < 0" ); + } + if ( end > _data.length ) { + throw new IndexOutOfBoundsException( "end index < " + _data.length ); + } + TIntArrayList list = new TIntArrayList( end - begin ); + for ( int i = begin; i < end; i++ ) { + list.add( _data[ i ] ); + } + return list; + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return toArray( 0, _pos ); + } + + + /** {@inheritDoc} */ + public int[] toArray( int offset, int len ) { + int[] rv = new int[ len ]; + toArray( rv, offset, len ); + return rv; + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + int len = dest.length; + if ( dest.length > _pos ) { + len = _pos; + dest[len] = no_entry_value; + } + toArray( dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest, int offset, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( _data, offset, dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest, int source_pos, int dest_pos, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( source_pos < 0 || source_pos >= _pos ) { + throw new ArrayIndexOutOfBoundsException( source_pos ); + } + System.arraycopy( _data, source_pos, dest, dest_pos, len ); + return dest; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TIntList ) ) return false; + + if ( other instanceof TIntArrayList ) { + TIntArrayList that = ( TIntArrayList )other; + if ( that.size() != this.size() ) return false; + + for ( int i = _pos; i-- > 0; ) { + if ( this._data[ i ] != that._data[ i ] ) { + return false; + } + } + return true; + } + else { + TIntList that = ( TIntList )other; + if ( that.size() != this.size() ) return false; + + for( int i = 0; i < _pos; i++ ) { + if ( this._data[ i ] != that.get( i ) ) { + return false; + } + } + return true; + } + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = _pos; i-- > 0; ) { + h += HashFunctions.hash( _data[ i ] ); + } + return h; + } + + + // procedures + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + for ( int i = 0; i < _pos; i++ ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachDescending( TIntProcedure procedure ) { + for ( int i = _pos; i-- > 0; ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + // sorting + + /** {@inheritDoc} */ + public void sort() { + Arrays.sort( _data, 0, _pos ); + } + + + /** {@inheritDoc} */ + public void sort( int fromIndex, int toIndex ) { + Arrays.sort( _data, fromIndex, toIndex ); + } + + + // filling + + /** {@inheritDoc} */ + public void fill( int val ) { + Arrays.fill( _data, 0, _pos, val ); + } + + + /** {@inheritDoc} */ + public void fill( int fromIndex, int toIndex, int val ) { + if ( toIndex > _pos ) { + ensureCapacity( toIndex ); + _pos = toIndex; + } + Arrays.fill( _data, fromIndex, toIndex, val ); + } + + + // searching + + /** {@inheritDoc} */ + public int binarySearch( int value ) { + return binarySearch( value, 0, _pos ); + } + + + /** {@inheritDoc} */ + public int binarySearch(int value, int fromIndex, int toIndex) { + if ( fromIndex < 0 ) { + throw new ArrayIndexOutOfBoundsException( fromIndex ); + } + if ( toIndex > _pos ) { + throw new ArrayIndexOutOfBoundsException( toIndex ); + } + + int low = fromIndex; + int high = toIndex - 1; + + while ( low <= high ) { + int mid = ( low + high ) >>> 1; + int midVal = _data[ mid ]; + + if ( midVal < value ) { + low = mid + 1; + } + else if ( midVal > value ) { + high = mid - 1; + } + else { + return mid; // value found + } + } + return -( low + 1 ); // value not found. + } + + + /** {@inheritDoc} */ + public int indexOf( int value ) { + return indexOf( 0, value ); + } + + + /** {@inheritDoc} */ + public int indexOf( int offset, int value ) { + for ( int i = offset; i < _pos; i++ ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int value ) { + return lastIndexOf( _pos, value ); + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int offset, int value ) { + for ( int i = offset; i-- > 0; ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public boolean contains( int value ) { + return lastIndexOf( value ) >= 0; + } + + + /** {@inheritDoc} */ + public TIntList grep( TIntProcedure condition ) { + TIntArrayList list = new TIntArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public TIntList inverseGrep( TIntProcedure condition ) { + TIntArrayList list = new TIntArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( !condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public int max() { + if ( size() == 0 ) { + throw new IllegalStateException("cannot find maximum of an empty list"); + } + int max = Integer.MIN_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[ i ] > max ) { + max = _data[ i ]; + } + } + return max; + } + + + /** {@inheritDoc} */ + public int min() { + if ( size() == 0 ) { + throw new IllegalStateException( "cannot find minimum of an empty list" ); + } + int min = Integer.MAX_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[i] < min ) { + min = _data[i]; + } + } + return min; + } + + + /** {@inheritDoc} */ + public int sum() { + int sum = 0; + for ( int i = 0; i < _pos; i++ ) { + sum += _data[ i ]; + } + return sum; + } + + + // stringification + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = 0, end = _pos - 1; i < end; i++ ) { + buf.append( _data[ i ] ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _data[ _pos - 1 ] ); + } + buf.append( "}" ); + return buf.toString(); + } + + + /** TIntArrayList iterator */ + class TIntArrayIterator implements TIntIterator { + + /** Index of element to be returned by subsequent call to next. */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + + TIntArrayIterator( int index ) { + cursor = index; + } + + + /** {@inheritDoc} */ + public boolean hasNext() { + return cursor < size(); + } + + + /** {@inheritDoc} */ + public int next() { + try { + int next = get( cursor ); + lastRet = cursor++; + return next; + } catch ( IndexOutOfBoundsException e ) { + throw new NoSuchElementException(); + } + } + + + /** {@inheritDoc} */ + public void remove() { + if ( lastRet == -1 ) + throw new IllegalStateException(); + + try { + TIntArrayList.this.remove( lastRet, 1); + if ( lastRet < cursor ) + cursor--; + lastRet = -1; + } catch ( IndexOutOfBoundsException e ) { + throw new ConcurrentModificationException(); + } + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // POSITION + out.writeInt( _pos ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + + // ENTRIES + int len = _data.length; + out.writeInt( len ); + for( int i = 0; i < len; i++ ) { + out.writeInt( _data[ i ] ); + } + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // POSITION + _pos = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + + // ENTRIES + int len = in.readInt(); + _data = new int[ len ]; + for( int i = 0; i < len; i++ ) { + _data[ i ] = in.readInt(); + } + } +} // TIntArrayList diff --git a/src/gnu/trove/list/array/TLongArrayList.java b/src/gnu/trove/list/array/TLongArrayList.java new file mode 100644 index 0000000..2e94a80 --- /dev/null +++ b/src/gnu/trove/list/array/TLongArrayList.java @@ -0,0 +1,1087 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.array; + +import gnu.trove.function.TLongFunction; +import gnu.trove.list.TLongList; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.TLongCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, array-backed list of long primitives. + */ +public class TLongArrayList implements TLongList, Externalizable { + static final long serialVersionUID = 1L; + + /** the data of the list */ + protected long[] _data; + + /** the index after the last entry in the list */ + protected int _pos; + + /** the default capacity for new lists */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + /** the long value that represents null */ + protected long no_entry_value; + + + /** + * Creates a new TLongArrayList instance with the + * default capacity. + */ + @SuppressWarnings({}) + public TLongArrayList() { + this( DEFAULT_CAPACITY, ( long ) 0 ); + } + + + /** + * Creates a new TLongArrayList instance with the + * specified capacity. + * + * @param capacity an int value + */ + @SuppressWarnings({}) + public TLongArrayList( int capacity ) { + this( capacity, ( long ) 0 ); + } + + + /** + * Creates a new TLongArrayList instance with the + * specified capacity. + * + * @param capacity an int value + * @param no_entry_value an long value that represents null. + */ + public TLongArrayList( int capacity, long no_entry_value ) { + _data = new long[ capacity ]; + _pos = 0; + this.no_entry_value = no_entry_value; + } + + /** + * Creates a new TLongArrayList instance that contains + * a copy of the collection passed to us. + * + * @param collection the collection to copy + */ + public TLongArrayList ( TLongCollection collection ) { + this( collection.size() ); + addAll( collection ); + } + + + /** + * Creates a new TLongArrayList instance whose + * capacity is the length of values array and whose + * initial contents are the specified values. + *

+ * A defensive copy of the given values is held by the new instance. + * + * @param values an long[] value + */ + public TLongArrayList( long[] values ) { + this( values.length ); + add( values ); + } + + protected TLongArrayList(long[] values, long no_entry_value, boolean wrap) { + if (!wrap) + throw new IllegalStateException("Wrong call"); + + if (values == null) + throw new IllegalArgumentException("values can not be null"); + + _data = values; + _pos = values.length; + this.no_entry_value = no_entry_value; + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @return + */ + public static TLongArrayList wrap(long[] values) { + return wrap(values, ( long ) 0); + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @param no_entry_value + * @return + */ + public static TLongArrayList wrap(long[] values, long no_entry_value) { + return new TLongArrayList(values, no_entry_value, true) { + /** + * Growing the wrapped external array is not allow + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) + throw new IllegalStateException("Can not grow ArrayList wrapped external array"); + } + }; + } + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + // sizing + + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + public void ensureCapacity( int capacity ) { + if ( capacity > _data.length ) { + int newCap = Math.max( _data.length << 1, capacity ); + long[] tmp = new long[ newCap ]; + System.arraycopy( _data, 0, tmp, 0, _data.length ); + _data = tmp; + } + } + + + /** {@inheritDoc} */ + public int size() { + return _pos; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _pos == 0; + } + + + /** + * Sheds any excess capacity above and beyond the current size of the list. + */ + public void trimToSize() { + if ( _data.length > size() ) { + long[] tmp = new long[ size() ]; + toArray( tmp, 0, tmp.length ); + _data = tmp; + } + } + + + // modifying + + /** {@inheritDoc} */ + public boolean add( long val ) { + ensureCapacity( _pos + 1 ); + _data[ _pos++ ] = val; + return true; + } + + + /** {@inheritDoc} */ + public void add( long[] vals ) { + add( vals, 0, vals.length ); + } + + + /** {@inheritDoc} */ + public void add( long[] vals, int offset, int length ) { + ensureCapacity( _pos + length ); + System.arraycopy( vals, offset, _data, _pos, length ); + _pos += length; + } + + + /** {@inheritDoc} */ + public void insert( int offset, long value ) { + if ( offset == _pos ) { + add( value ); + return; + } + ensureCapacity( _pos + 1 ); + // shift right + System.arraycopy( _data, offset, _data, offset + 1, _pos - offset ); + // insert + _data[ offset ] = value; + _pos++; + } + + + /** {@inheritDoc} */ + public void insert( int offset, long[] values ) { + insert( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void insert( int offset, long[] values, int valOffset, int len ) { + if ( offset == _pos ) { + add( values, valOffset, len ); + return; + } + + ensureCapacity( _pos + len ); + // shift right + System.arraycopy( _data, offset, _data, offset + len, _pos - offset ); + // insert + System.arraycopy( values, valOffset, _data, offset, len ); + _pos += len; + } + + + /** {@inheritDoc} */ + public long get( int offset ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + return _data[ offset ]; + } + + + /** + * Returns the value at the specified offset without doing any bounds checking. + */ + public long getQuick( int offset ) { + return _data[ offset ]; + } + + + /** {@inheritDoc} */ + public long set( int offset, long val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + + long prev_val = _data[ offset ]; + _data[ offset ] = val; + return prev_val; + } + + + /** {@inheritDoc} */ + public long replace( int offset, long val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + long old = _data[ offset ]; + _data[ offset ] = val; + return old; + } + + + /** {@inheritDoc} */ + public void set( int offset, long[] values ) { + set( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void set( int offset, long[] values, int valOffset, int length ) { + if ( offset < 0 || offset + length > _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( values, valOffset, _data, offset, length ); + } + + + /** + * Sets the value at the specified offset without doing any bounds checking. + */ + public void setQuick( int offset, long val ) { + _data[ offset ] = val; + } + + + /** {@inheritDoc} */ + public void clear() { + clear( DEFAULT_CAPACITY ); + } + + + /** + * Flushes the internal state of the list, setting the capacity of the empty list to + * capacity. + */ + public void clear( int capacity ) { + _data = new long[ capacity ]; + _pos = 0; + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. + */ + public void reset() { + _pos = 0; + Arrays.fill( _data, no_entry_value ); + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. This method differs from + * {@link #reset()} in that it does not clear the old values in the backing array. + * Thus, it is possible for getQuick to return stale data if this method is used and + * the caller is careless about bounds checking. + */ + public void resetQuick() { + _pos = 0; + } + + + /** {@inheritDoc} */ + public boolean remove( long value ) { + for ( int index = 0; index < _pos; index++ ) { + if ( value == _data[index] ) { + remove( index, 1 ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public long removeAt( int offset ) { + long old = get( offset ); + remove( offset, 1 ); + return old; + } + + + /** {@inheritDoc} */ + public void remove( int offset, int length ) { + if ( length == 0 ) return; + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + if ( offset == 0 ) { + // data at the front + System.arraycopy( _data, length, _data, 0, _pos - length ); + } + else if ( _pos - length == offset ) { + // no copy to make, decrementing pos "deletes" values at + // the end + } + else { + // data in the middle + System.arraycopy( _data, offset + length, _data, offset, + _pos - ( offset + length ) ); + } + _pos -= length; + // no need to clear old values beyond _pos, because this is a + // primitive collection and 0 takes as much room as any other + // value + } + + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongArrayIterator( 0 ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + if ( this == collection ) { + return true; + } + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Long element : collection ) { + long e = element.longValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + boolean changed = false; + for ( long element : array ) { + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] data = _data; + + for ( int i = _pos; i-- > 0; ) { + if ( Arrays.binarySearch( array, data[i] ) < 0 ) { + remove( i, 1 ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + for ( int i = _pos; i-- > 0; ) { + _data[ i ] = function.execute( _data[ i ] ); + } + } + + + /** {@inheritDoc} */ + public void reverse() { + reverse( 0, _pos ); + } + + + /** {@inheritDoc} */ + public void reverse( int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( i, j ); + } + } + + + /** {@inheritDoc} */ + public void shuffle( Random rand ) { + for ( int i = _pos; i-- > 1; ) { + swap( i, rand.nextInt( i ) ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int i, int j ) { + long tmp = _data[ i ]; + _data[ i ] = _data[ j ]; + _data[ j ] = tmp; + } + + + // copying + + /** {@inheritDoc} */ + public TLongList subList( int begin, int end ) { + if ( end < begin ) { + throw new IllegalArgumentException( "end index " + end + + " greater than begin index " + begin ); + } + if ( begin < 0 ) { + throw new IndexOutOfBoundsException( "begin index can not be < 0" ); + } + if ( end > _data.length ) { + throw new IndexOutOfBoundsException( "end index < " + _data.length ); + } + TLongArrayList list = new TLongArrayList( end - begin ); + for ( int i = begin; i < end; i++ ) { + list.add( _data[ i ] ); + } + return list; + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return toArray( 0, _pos ); + } + + + /** {@inheritDoc} */ + public long[] toArray( int offset, int len ) { + long[] rv = new long[ len ]; + toArray( rv, offset, len ); + return rv; + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + int len = dest.length; + if ( dest.length > _pos ) { + len = _pos; + dest[len] = no_entry_value; + } + toArray( dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest, int offset, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( _data, offset, dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest, int source_pos, int dest_pos, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( source_pos < 0 || source_pos >= _pos ) { + throw new ArrayIndexOutOfBoundsException( source_pos ); + } + System.arraycopy( _data, source_pos, dest, dest_pos, len ); + return dest; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TLongList ) ) return false; + + if ( other instanceof TLongArrayList ) { + TLongArrayList that = ( TLongArrayList )other; + if ( that.size() != this.size() ) return false; + + for ( int i = _pos; i-- > 0; ) { + if ( this._data[ i ] != that._data[ i ] ) { + return false; + } + } + return true; + } + else { + TLongList that = ( TLongList )other; + if ( that.size() != this.size() ) return false; + + for( int i = 0; i < _pos; i++ ) { + if ( this._data[ i ] != that.get( i ) ) { + return false; + } + } + return true; + } + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = _pos; i-- > 0; ) { + h += HashFunctions.hash( _data[ i ] ); + } + return h; + } + + + // procedures + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + for ( int i = 0; i < _pos; i++ ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachDescending( TLongProcedure procedure ) { + for ( int i = _pos; i-- > 0; ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + // sorting + + /** {@inheritDoc} */ + public void sort() { + Arrays.sort( _data, 0, _pos ); + } + + + /** {@inheritDoc} */ + public void sort( int fromIndex, int toIndex ) { + Arrays.sort( _data, fromIndex, toIndex ); + } + + + // filling + + /** {@inheritDoc} */ + public void fill( long val ) { + Arrays.fill( _data, 0, _pos, val ); + } + + + /** {@inheritDoc} */ + public void fill( int fromIndex, int toIndex, long val ) { + if ( toIndex > _pos ) { + ensureCapacity( toIndex ); + _pos = toIndex; + } + Arrays.fill( _data, fromIndex, toIndex, val ); + } + + + // searching + + /** {@inheritDoc} */ + public int binarySearch( long value ) { + return binarySearch( value, 0, _pos ); + } + + + /** {@inheritDoc} */ + public int binarySearch(long value, int fromIndex, int toIndex) { + if ( fromIndex < 0 ) { + throw new ArrayIndexOutOfBoundsException( fromIndex ); + } + if ( toIndex > _pos ) { + throw new ArrayIndexOutOfBoundsException( toIndex ); + } + + int low = fromIndex; + int high = toIndex - 1; + + while ( low <= high ) { + int mid = ( low + high ) >>> 1; + long midVal = _data[ mid ]; + + if ( midVal < value ) { + low = mid + 1; + } + else if ( midVal > value ) { + high = mid - 1; + } + else { + return mid; // value found + } + } + return -( low + 1 ); // value not found. + } + + + /** {@inheritDoc} */ + public int indexOf( long value ) { + return indexOf( 0, value ); + } + + + /** {@inheritDoc} */ + public int indexOf( int offset, long value ) { + for ( int i = offset; i < _pos; i++ ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public int lastIndexOf( long value ) { + return lastIndexOf( _pos, value ); + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int offset, long value ) { + for ( int i = offset; i-- > 0; ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public boolean contains( long value ) { + return lastIndexOf( value ) >= 0; + } + + + /** {@inheritDoc} */ + public TLongList grep( TLongProcedure condition ) { + TLongArrayList list = new TLongArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public TLongList inverseGrep( TLongProcedure condition ) { + TLongArrayList list = new TLongArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( !condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public long max() { + if ( size() == 0 ) { + throw new IllegalStateException("cannot find maximum of an empty list"); + } + long max = Long.MIN_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[ i ] > max ) { + max = _data[ i ]; + } + } + return max; + } + + + /** {@inheritDoc} */ + public long min() { + if ( size() == 0 ) { + throw new IllegalStateException( "cannot find minimum of an empty list" ); + } + long min = Long.MAX_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[i] < min ) { + min = _data[i]; + } + } + return min; + } + + + /** {@inheritDoc} */ + public long sum() { + long sum = 0; + for ( int i = 0; i < _pos; i++ ) { + sum += _data[ i ]; + } + return sum; + } + + + // stringification + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = 0, end = _pos - 1; i < end; i++ ) { + buf.append( _data[ i ] ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _data[ _pos - 1 ] ); + } + buf.append( "}" ); + return buf.toString(); + } + + + /** TLongArrayList iterator */ + class TLongArrayIterator implements TLongIterator { + + /** Index of element to be returned by subsequent call to next. */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + + TLongArrayIterator( int index ) { + cursor = index; + } + + + /** {@inheritDoc} */ + public boolean hasNext() { + return cursor < size(); + } + + + /** {@inheritDoc} */ + public long next() { + try { + long next = get( cursor ); + lastRet = cursor++; + return next; + } catch ( IndexOutOfBoundsException e ) { + throw new NoSuchElementException(); + } + } + + + /** {@inheritDoc} */ + public void remove() { + if ( lastRet == -1 ) + throw new IllegalStateException(); + + try { + TLongArrayList.this.remove( lastRet, 1); + if ( lastRet < cursor ) + cursor--; + lastRet = -1; + } catch ( IndexOutOfBoundsException e ) { + throw new ConcurrentModificationException(); + } + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // POSITION + out.writeInt( _pos ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + + // ENTRIES + int len = _data.length; + out.writeInt( len ); + for( int i = 0; i < len; i++ ) { + out.writeLong( _data[ i ] ); + } + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // POSITION + _pos = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + + // ENTRIES + int len = in.readInt(); + _data = new long[ len ]; + for( int i = 0; i < len; i++ ) { + _data[ i ] = in.readLong(); + } + } +} // TLongArrayList diff --git a/src/gnu/trove/list/array/TShortArrayList.java b/src/gnu/trove/list/array/TShortArrayList.java new file mode 100644 index 0000000..f70a02a --- /dev/null +++ b/src/gnu/trove/list/array/TShortArrayList.java @@ -0,0 +1,1087 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.array; + +import gnu.trove.function.TShortFunction; +import gnu.trove.list.TShortList; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.iterator.TShortIterator; +import gnu.trove.TShortCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, array-backed list of short primitives. + */ +public class TShortArrayList implements TShortList, Externalizable { + static final long serialVersionUID = 1L; + + /** the data of the list */ + protected short[] _data; + + /** the index after the last entry in the list */ + protected int _pos; + + /** the default capacity for new lists */ + protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + /** the short value that represents null */ + protected short no_entry_value; + + + /** + * Creates a new TShortArrayList instance with the + * default capacity. + */ + @SuppressWarnings({}) + public TShortArrayList() { + this( DEFAULT_CAPACITY, ( short ) 0 ); + } + + + /** + * Creates a new TShortArrayList instance with the + * specified capacity. + * + * @param capacity an int value + */ + @SuppressWarnings({}) + public TShortArrayList( int capacity ) { + this( capacity, ( short ) 0 ); + } + + + /** + * Creates a new TShortArrayList instance with the + * specified capacity. + * + * @param capacity an int value + * @param no_entry_value an short value that represents null. + */ + public TShortArrayList( int capacity, short no_entry_value ) { + _data = new short[ capacity ]; + _pos = 0; + this.no_entry_value = no_entry_value; + } + + /** + * Creates a new TShortArrayList instance that contains + * a copy of the collection passed to us. + * + * @param collection the collection to copy + */ + public TShortArrayList ( TShortCollection collection ) { + this( collection.size() ); + addAll( collection ); + } + + + /** + * Creates a new TShortArrayList instance whose + * capacity is the length of values array and whose + * initial contents are the specified values. + *

+ * A defensive copy of the given values is held by the new instance. + * + * @param values an short[] value + */ + public TShortArrayList( short[] values ) { + this( values.length ); + add( values ); + } + + protected TShortArrayList(short[] values, short no_entry_value, boolean wrap) { + if (!wrap) + throw new IllegalStateException("Wrong call"); + + if (values == null) + throw new IllegalArgumentException("values can not be null"); + + _data = values; + _pos = values.length; + this.no_entry_value = no_entry_value; + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @return + */ + public static TShortArrayList wrap(short[] values) { + return wrap(values, ( short ) 0); + } + + /** + * Returns a primitive List implementation that wraps around the given primitive array. + *

+ * NOTE: mutating operation are allowed as long as the List does not grow. In that case + * an IllegalStateException will be thrown + * + * @param values + * @param no_entry_value + * @return + */ + public static TShortArrayList wrap(short[] values, short no_entry_value) { + return new TShortArrayList(values, no_entry_value, true) { + /** + * Growing the wrapped external array is not allow + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) + throw new IllegalStateException("Can not grow ArrayList wrapped external array"); + } + }; + } + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + // sizing + + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + public void ensureCapacity( int capacity ) { + if ( capacity > _data.length ) { + int newCap = Math.max( _data.length << 1, capacity ); + short[] tmp = new short[ newCap ]; + System.arraycopy( _data, 0, tmp, 0, _data.length ); + _data = tmp; + } + } + + + /** {@inheritDoc} */ + public int size() { + return _pos; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _pos == 0; + } + + + /** + * Sheds any excess capacity above and beyond the current size of the list. + */ + public void trimToSize() { + if ( _data.length > size() ) { + short[] tmp = new short[ size() ]; + toArray( tmp, 0, tmp.length ); + _data = tmp; + } + } + + + // modifying + + /** {@inheritDoc} */ + public boolean add( short val ) { + ensureCapacity( _pos + 1 ); + _data[ _pos++ ] = val; + return true; + } + + + /** {@inheritDoc} */ + public void add( short[] vals ) { + add( vals, 0, vals.length ); + } + + + /** {@inheritDoc} */ + public void add( short[] vals, int offset, int length ) { + ensureCapacity( _pos + length ); + System.arraycopy( vals, offset, _data, _pos, length ); + _pos += length; + } + + + /** {@inheritDoc} */ + public void insert( int offset, short value ) { + if ( offset == _pos ) { + add( value ); + return; + } + ensureCapacity( _pos + 1 ); + // shift right + System.arraycopy( _data, offset, _data, offset + 1, _pos - offset ); + // insert + _data[ offset ] = value; + _pos++; + } + + + /** {@inheritDoc} */ + public void insert( int offset, short[] values ) { + insert( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void insert( int offset, short[] values, int valOffset, int len ) { + if ( offset == _pos ) { + add( values, valOffset, len ); + return; + } + + ensureCapacity( _pos + len ); + // shift right + System.arraycopy( _data, offset, _data, offset + len, _pos - offset ); + // insert + System.arraycopy( values, valOffset, _data, offset, len ); + _pos += len; + } + + + /** {@inheritDoc} */ + public short get( int offset ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + return _data[ offset ]; + } + + + /** + * Returns the value at the specified offset without doing any bounds checking. + */ + public short getQuick( int offset ) { + return _data[ offset ]; + } + + + /** {@inheritDoc} */ + public short set( int offset, short val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + + short prev_val = _data[ offset ]; + _data[ offset ] = val; + return prev_val; + } + + + /** {@inheritDoc} */ + public short replace( int offset, short val ) { + if ( offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + short old = _data[ offset ]; + _data[ offset ] = val; + return old; + } + + + /** {@inheritDoc} */ + public void set( int offset, short[] values ) { + set( offset, values, 0, values.length ); + } + + + /** {@inheritDoc} */ + public void set( int offset, short[] values, int valOffset, int length ) { + if ( offset < 0 || offset + length > _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( values, valOffset, _data, offset, length ); + } + + + /** + * Sets the value at the specified offset without doing any bounds checking. + */ + public void setQuick( int offset, short val ) { + _data[ offset ] = val; + } + + + /** {@inheritDoc} */ + public void clear() { + clear( DEFAULT_CAPACITY ); + } + + + /** + * Flushes the internal state of the list, setting the capacity of the empty list to + * capacity. + */ + public void clear( int capacity ) { + _data = new short[ capacity ]; + _pos = 0; + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. + */ + public void reset() { + _pos = 0; + Arrays.fill( _data, no_entry_value ); + } + + + /** + * Sets the size of the list to 0, but does not change its capacity. This method can + * be used as an alternative to the {@link #clear()} method if you want to recycle a + * list without allocating new backing arrays. This method differs from + * {@link #reset()} in that it does not clear the old values in the backing array. + * Thus, it is possible for getQuick to return stale data if this method is used and + * the caller is careless about bounds checking. + */ + public void resetQuick() { + _pos = 0; + } + + + /** {@inheritDoc} */ + public boolean remove( short value ) { + for ( int index = 0; index < _pos; index++ ) { + if ( value == _data[index] ) { + remove( index, 1 ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public short removeAt( int offset ) { + short old = get( offset ); + remove( offset, 1 ); + return old; + } + + + /** {@inheritDoc} */ + public void remove( int offset, int length ) { + if ( length == 0 ) return; + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + if ( offset == 0 ) { + // data at the front + System.arraycopy( _data, length, _data, 0, _pos - length ); + } + else if ( _pos - length == offset ) { + // no copy to make, decrementing pos "deletes" values at + // the end + } + else { + // data in the middle + System.arraycopy( _data, offset + length, _data, offset, + _pos - ( offset + length ) ); + } + _pos -= length; + // no need to clear old values beyond _pos, because this is a + // primitive collection and 0 takes as much room as any other + // value + } + + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortArrayIterator( 0 ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + if ( this == collection ) { + return true; + } + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Short element : collection ) { + short e = element.shortValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + boolean changed = false; + for ( short element : array ) { + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] data = _data; + + for ( int i = _pos; i-- > 0; ) { + if ( Arrays.binarySearch( array, data[i] ) < 0 ) { + remove( i, 1 ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + for ( int i = _pos; i-- > 0; ) { + _data[ i ] = function.execute( _data[ i ] ); + } + } + + + /** {@inheritDoc} */ + public void reverse() { + reverse( 0, _pos ); + } + + + /** {@inheritDoc} */ + public void reverse( int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( i, j ); + } + } + + + /** {@inheritDoc} */ + public void shuffle( Random rand ) { + for ( int i = _pos; i-- > 1; ) { + swap( i, rand.nextInt( i ) ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int i, int j ) { + short tmp = _data[ i ]; + _data[ i ] = _data[ j ]; + _data[ j ] = tmp; + } + + + // copying + + /** {@inheritDoc} */ + public TShortList subList( int begin, int end ) { + if ( end < begin ) { + throw new IllegalArgumentException( "end index " + end + + " greater than begin index " + begin ); + } + if ( begin < 0 ) { + throw new IndexOutOfBoundsException( "begin index can not be < 0" ); + } + if ( end > _data.length ) { + throw new IndexOutOfBoundsException( "end index < " + _data.length ); + } + TShortArrayList list = new TShortArrayList( end - begin ); + for ( int i = begin; i < end; i++ ) { + list.add( _data[ i ] ); + } + return list; + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return toArray( 0, _pos ); + } + + + /** {@inheritDoc} */ + public short[] toArray( int offset, int len ) { + short[] rv = new short[ len ]; + toArray( rv, offset, len ); + return rv; + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + int len = dest.length; + if ( dest.length > _pos ) { + len = _pos; + dest[len] = no_entry_value; + } + toArray( dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest, int offset, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( offset < 0 || offset >= _pos ) { + throw new ArrayIndexOutOfBoundsException( offset ); + } + System.arraycopy( _data, offset, dest, 0, len ); + return dest; + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest, int source_pos, int dest_pos, int len ) { + if ( len == 0 ) { + return dest; // nothing to copy + } + if ( source_pos < 0 || source_pos >= _pos ) { + throw new ArrayIndexOutOfBoundsException( source_pos ); + } + System.arraycopy( _data, source_pos, dest, dest_pos, len ); + return dest; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TShortList ) ) return false; + + if ( other instanceof TShortArrayList ) { + TShortArrayList that = ( TShortArrayList )other; + if ( that.size() != this.size() ) return false; + + for ( int i = _pos; i-- > 0; ) { + if ( this._data[ i ] != that._data[ i ] ) { + return false; + } + } + return true; + } + else { + TShortList that = ( TShortList )other; + if ( that.size() != this.size() ) return false; + + for( int i = 0; i < _pos; i++ ) { + if ( this._data[ i ] != that.get( i ) ) { + return false; + } + } + return true; + } + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = _pos; i-- > 0; ) { + h += HashFunctions.hash( _data[ i ] ); + } + return h; + } + + + // procedures + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + for ( int i = 0; i < _pos; i++ ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachDescending( TShortProcedure procedure ) { + for ( int i = _pos; i-- > 0; ) { + if ( !procedure.execute( _data[ i ] ) ) { + return false; + } + } + return true; + } + + + // sorting + + /** {@inheritDoc} */ + public void sort() { + Arrays.sort( _data, 0, _pos ); + } + + + /** {@inheritDoc} */ + public void sort( int fromIndex, int toIndex ) { + Arrays.sort( _data, fromIndex, toIndex ); + } + + + // filling + + /** {@inheritDoc} */ + public void fill( short val ) { + Arrays.fill( _data, 0, _pos, val ); + } + + + /** {@inheritDoc} */ + public void fill( int fromIndex, int toIndex, short val ) { + if ( toIndex > _pos ) { + ensureCapacity( toIndex ); + _pos = toIndex; + } + Arrays.fill( _data, fromIndex, toIndex, val ); + } + + + // searching + + /** {@inheritDoc} */ + public int binarySearch( short value ) { + return binarySearch( value, 0, _pos ); + } + + + /** {@inheritDoc} */ + public int binarySearch(short value, int fromIndex, int toIndex) { + if ( fromIndex < 0 ) { + throw new ArrayIndexOutOfBoundsException( fromIndex ); + } + if ( toIndex > _pos ) { + throw new ArrayIndexOutOfBoundsException( toIndex ); + } + + int low = fromIndex; + int high = toIndex - 1; + + while ( low <= high ) { + int mid = ( low + high ) >>> 1; + short midVal = _data[ mid ]; + + if ( midVal < value ) { + low = mid + 1; + } + else if ( midVal > value ) { + high = mid - 1; + } + else { + return mid; // value found + } + } + return -( low + 1 ); // value not found. + } + + + /** {@inheritDoc} */ + public int indexOf( short value ) { + return indexOf( 0, value ); + } + + + /** {@inheritDoc} */ + public int indexOf( int offset, short value ) { + for ( int i = offset; i < _pos; i++ ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public int lastIndexOf( short value ) { + return lastIndexOf( _pos, value ); + } + + + /** {@inheritDoc} */ + public int lastIndexOf( int offset, short value ) { + for ( int i = offset; i-- > 0; ) { + if ( _data[ i ] == value ) { + return i; + } + } + return -1; + } + + + /** {@inheritDoc} */ + public boolean contains( short value ) { + return lastIndexOf( value ) >= 0; + } + + + /** {@inheritDoc} */ + public TShortList grep( TShortProcedure condition ) { + TShortArrayList list = new TShortArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public TShortList inverseGrep( TShortProcedure condition ) { + TShortArrayList list = new TShortArrayList(); + for ( int i = 0; i < _pos; i++ ) { + if ( !condition.execute( _data[ i ] ) ) { + list.add( _data[ i ] ); + } + } + return list; + } + + + /** {@inheritDoc} */ + public short max() { + if ( size() == 0 ) { + throw new IllegalStateException("cannot find maximum of an empty list"); + } + short max = Short.MIN_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[ i ] > max ) { + max = _data[ i ]; + } + } + return max; + } + + + /** {@inheritDoc} */ + public short min() { + if ( size() == 0 ) { + throw new IllegalStateException( "cannot find minimum of an empty list" ); + } + short min = Short.MAX_VALUE; + for ( int i = 0; i < _pos; i++ ) { + if ( _data[i] < min ) { + min = _data[i]; + } + } + return min; + } + + + /** {@inheritDoc} */ + public short sum() { + short sum = 0; + for ( int i = 0; i < _pos; i++ ) { + sum += _data[ i ]; + } + return sum; + } + + + // stringification + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = 0, end = _pos - 1; i < end; i++ ) { + buf.append( _data[ i ] ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _data[ _pos - 1 ] ); + } + buf.append( "}" ); + return buf.toString(); + } + + + /** TShortArrayList iterator */ + class TShortArrayIterator implements TShortIterator { + + /** Index of element to be returned by subsequent call to next. */ + private int cursor = 0; + + /** + * Index of element returned by most recent call to next or + * previous. Reset to -1 if this element is deleted by a call + * to remove. + */ + int lastRet = -1; + + + TShortArrayIterator( int index ) { + cursor = index; + } + + + /** {@inheritDoc} */ + public boolean hasNext() { + return cursor < size(); + } + + + /** {@inheritDoc} */ + public short next() { + try { + short next = get( cursor ); + lastRet = cursor++; + return next; + } catch ( IndexOutOfBoundsException e ) { + throw new NoSuchElementException(); + } + } + + + /** {@inheritDoc} */ + public void remove() { + if ( lastRet == -1 ) + throw new IllegalStateException(); + + try { + TShortArrayList.this.remove( lastRet, 1); + if ( lastRet < cursor ) + cursor--; + lastRet = -1; + } catch ( IndexOutOfBoundsException e ) { + throw new ConcurrentModificationException(); + } + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // POSITION + out.writeInt( _pos ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + + // ENTRIES + int len = _data.length; + out.writeInt( len ); + for( int i = 0; i < len; i++ ) { + out.writeShort( _data[ i ] ); + } + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // POSITION + _pos = in.readInt(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + + // ENTRIES + int len = in.readInt(); + _data = new short[ len ]; + for( int i = 0; i < len; i++ ) { + _data[ i ] = in.readShort(); + } + } +} // TShortArrayList diff --git a/src/gnu/trove/list/linked/TByteLinkedList.java b/src/gnu/trove/list/linked/TByteLinkedList.java new file mode 100644 index 0000000..709e08b --- /dev/null +++ b/src/gnu/trove/list/linked/TByteLinkedList.java @@ -0,0 +1,1059 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// Copyright (c) 2011, Johan Parent All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.linked; + +import gnu.trove.function.TByteFunction; +import gnu.trove.list.TByteList; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.TByteCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, double linked list of byte primitives. + */ +public class TByteLinkedList implements TByteList, Externalizable { + private byte no_entry_value; + private int size; + + private TByteLink head = null; + private TByteLink tail = head; + + public TByteLinkedList() { + this( Constants.DEFAULT_BYTE_NO_ENTRY_VALUE ); + } + + public TByteLinkedList(byte no_entry_value) { + this.no_entry_value = no_entry_value; + } + + public TByteLinkedList(TByteList list) { + no_entry_value = list.getNoEntryValue(); + // + for (TByteIterator iterator = list.iterator(); iterator.hasNext();) { + byte next = iterator.next(); + add(next); + } + } + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + public boolean add(byte val) { + TByteLink l = new TByteLink(val); + if (no(head)) { + head = l; + tail = l; + } else { + l.setPrevious(tail); + tail.setNext(l); + // + tail = l; + } + + size++; + return true; + } + + /** {@inheritDoc} */ + public void add(byte[] vals) { + for (byte val : vals) { + add(val); + } + } + + /** {@inheritDoc} */ + public void add(byte[] vals, int offset, int length) { + for (int i = 0; i < length; i++) { + byte val = vals[offset + i]; + add(val); + } + } + + /** {@inheritDoc} */ + public void insert(int offset, byte value) { + TByteLinkedList tmp = new TByteLinkedList(); + tmp.add(value); + insert(offset, tmp); + } + + /** {@inheritDoc} */ + public void insert(int offset, byte[] values) { + insert(offset, link(values, 0, values.length)); + } + + /** {@inheritDoc} */ + public void insert(int offset, byte[] values, int valOffset, int len) { + insert(offset, link(values, valOffset, len)); + } + + void insert(int offset, TByteLinkedList tmp) { + TByteLink l = getLinkAt(offset); + + size = size + tmp.size; + // + if (l == head) { + // Add in front + tmp.tail.setNext(head); + head.setPrevious(tmp.tail); + head = tmp.head; + + return; + } + + if (no(l)) { + if (size == 0) { + // New empty list + head = tmp.head; + tail = tmp.tail; + } else { + // append + tail.setNext(tmp.head); + tmp.head.setPrevious(tail); + tail = tmp.tail; + } + } else { + TByteLink prev = l.getPrevious(); + l.getPrevious().setNext(tmp.head); + + // Link by behind tmp + tmp.tail.setNext(l); + l.setPrevious(tmp.tail); + + tmp.head.setPrevious(prev); + } + } + + static TByteLinkedList link(byte[] values, int valOffset, int len) { + TByteLinkedList ret = new TByteLinkedList(); + + for (int i = 0; i < len; i++) { + ret.add(values[valOffset + i]); + } + + return ret; + } + + /** {@inheritDoc} */ + public byte get(int offset) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TByteLink l = getLinkAt(offset); + // + if (no(l)) + return no_entry_value; + + return l.getValue(); + } + + /** + * Returns the link at the given offset. + *

+ * A simple bisection criteria is used to keep the worst case complexity equal to + * O(n/2) where n = size(). Simply start from head of list or tail depending on offset + * and list size. + * + * @param offset of the link + * @return link or null if non-existent + */ + public TByteLink getLinkAt(int offset) { + if (offset >= size()) + return null; + + if (offset <= (size() >>> 1)) + return getLink(head, 0, offset, true); + else + return getLink(tail, size() - 1, offset, false); + } + + /** + * Returns the link at absolute offset starting from given the initial link 'l' at index 'idx' + * + * @param l + * @param idx + * @param offset + * @return + */ + private static TByteLink getLink(TByteLink l, int idx, int offset) { + return getLink(l, idx, offset, true); + } + + /** + * Returns link at given absolute offset starting from link 'l' at index 'idx' + * @param l + * @param idx + * @param offset + * @param next + * @return + */ + private static TByteLink getLink(TByteLink l, int idx, int offset, boolean next) { + int i = idx; + // + while (got(l)) { + if (i == offset) { + return l; + } + + i = i + (next ? 1 : -1); + l = next ? l.getNext() : l.getPrevious(); + } + + return null; + } + + + /** {@inheritDoc} */ + public byte set(int offset, byte val) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TByteLink l = getLinkAt(offset); + // + if (no(l)) + throw new IndexOutOfBoundsException("at offset " + offset); + + byte prev = l.getValue(); + l.setValue(val); + return prev; + } + + /** {@inheritDoc} */ + public void set(int offset, byte[] values) { + set(offset, values, 0, values.length); + } + + /** {@inheritDoc} */ + public void set(int offset, byte[] values, int valOffset, int length) { + for (int i = 0; i < length; i++) { + byte value = values[valOffset + i]; + set(offset + i, value); + } + } + + /** {@inheritDoc} */ + public byte replace(int offset, byte val) { + return set(offset, val); + } + + /** {@inheritDoc} */ + public void clear() { + size = 0; + // + head = null; + tail = null; + } + + /** {@inheritDoc} */ + public boolean remove(byte value) { + boolean changed = false; + for (TByteLink l = head; got(l); l = l.getNext()) { + // + if (l.getValue() == value) { + changed = true; + // + removeLink(l); + } + } + + return changed; + } + + /** + * unlinks the give TByteLink from the list + * + * @param l + */ + private void removeLink(TByteLink l) { + if (no(l)) + return; + + size--; + + TByteLink prev = l.getPrevious(); + TByteLink next = l.getNext(); + + if (got(prev)) { + prev.setNext(next); + } else { + // No previous we must be head + head = next; + } + + if (got(next)) { + next.setPrevious(prev); + } else { + // No next so me must be tail + tail = prev; + } + // Unlink + l.setNext(null); + l.setPrevious(null); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + if (isEmpty()) + return false; + + for (Object o : collection) { + if (o instanceof Byte) { + Byte i = (Byte) o; + if (!(contains(i))) + return false; + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(TByteCollection collection) { + if (isEmpty()) + return false; + + for (TByteIterator it = collection.iterator(); it.hasNext();) { + byte i = it.next(); + if (!(contains(i))) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(byte[] array) { + if (isEmpty()) + return false; + + for (byte i : array) { + if (!contains(i)) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + boolean ret = false; + for (Byte v : collection) { + if (add(v.byteValue())) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(TByteCollection collection) { + boolean ret = false; + for (TByteIterator it = collection.iterator(); it.hasNext();) { + byte i = it.next(); + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(byte[] array) { + boolean ret = false; + for (byte i : array) { + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + boolean modified = false; + TByteIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(Byte.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(TByteCollection collection) { + boolean modified = false; + TByteIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(byte[] array) { + Arrays.sort(array); + + boolean modified = false; + TByteIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) < 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + boolean modified = false; + TByteIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(Byte.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(TByteCollection collection) { + boolean modified = false; + TByteIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(byte[] array) { + Arrays.sort(array); + + boolean modified = false; + TByteIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) >= 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public byte removeAt(int offset) { + TByteLink l = getLinkAt(offset); + if (no(l)) + throw new ArrayIndexOutOfBoundsException("no elemenet at " + offset); + + byte prev = l.getValue(); + removeLink(l); + return prev; + } + + /** {@inheritDoc} */ + public void remove(int offset, int length) { + for (int i = 0; i < length; i++) { + removeAt(offset); // since the list shrinks we don't need to use offset+i to get the next entry ;) + } + } + + /** {@inheritDoc} */ + public void transformValues(TByteFunction function) { + for (TByteLink l = head; got(l);) { + // + l.setValue(function.execute(l.getValue())); + // + l = l.getNext(); + } + } + + /** {@inheritDoc} */ + public void reverse() { + TByteLink h = head; + TByteLink t = tail; + TByteLink prev, next, tmp; + + // + TByteLink l = head; + while (got(l)) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // + head = t; + tail = h; + } + + /** {@inheritDoc} */ + public void reverse(int from, int to) { + if (from > to) + throw new IllegalArgumentException("from > to : " + from + ">" + to); + + TByteLink start = getLinkAt(from); + TByteLink stop = getLinkAt(to); + TByteLink prev, next; + TByteLink tmp = null; + + TByteLink tmpHead = start.getPrevious(); + + // + TByteLink l = start; + while (l != stop) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // At this point l == stop and tmp is the but last element { + if (got(tmp)) { + tmpHead.setNext(tmp); + stop.setPrevious(tmpHead); + } + start.setNext(stop); + stop.setPrevious(start); + } + + /** {@inheritDoc} */ + public void shuffle(Random rand) { + for (int i = 0; i < size; i++) { + TByteLink l = getLinkAt(rand.nextInt(size())); + removeLink(l); + add(l.getValue()); + } + } + + /** {@inheritDoc} */ + public TByteList subList(int begin, int end) { + if (end < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than end index " + end); + } + if (size < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than last index " + size); + } + if (begin < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + if (end > size) { + throw new IndexOutOfBoundsException("end index < " + size); + } + + TByteLinkedList ret = new TByteLinkedList(); + TByteLink tmp = getLinkAt(begin); + for (int i = begin; i < end; i++) { + ret.add(tmp.getValue()); // copy + tmp = tmp.getNext(); + } + + return ret; + } + + /** {@inheritDoc} */ + public byte[] toArray() { + return toArray(new byte[size], 0, size); + } + + /** {@inheritDoc} */ + public byte[] toArray(int offset, int len) { + return toArray(new byte[len], offset, 0, len); + } + + /** {@inheritDoc} */ + public byte[] toArray(byte[] dest) { + return toArray(dest, 0, size); + } + + /** {@inheritDoc} */ + public byte[] toArray(byte[] dest, int offset, int len) { + return toArray(dest, offset, 0, len); + } + + /** {@inheritDoc} */ + public byte[] toArray(byte[] dest, int source_pos, int dest_pos, int len) { + if (len == 0) { + return dest; // nothing to copy + } + if (source_pos < 0 || source_pos >= size()) { + throw new ArrayIndexOutOfBoundsException(source_pos); + } + + TByteLink tmp = getLinkAt(source_pos); + for (int i = 0; i < len; i++) { + dest[dest_pos + i] = tmp.getValue(); // copy + tmp = tmp.getNext(); + } + + return dest; + } + + /** {@inheritDoc} */ + public boolean forEach(TByteProcedure procedure) { + for (TByteLink l = head; got(l); l = l.getNext()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean forEachDescending(TByteProcedure procedure) { + for (TByteLink l = tail; got(l); l = l.getPrevious()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public void sort() { + sort(0, size); + } + + /** {@inheritDoc} */ + public void sort(int fromIndex, int toIndex) { + TByteList tmp = subList(fromIndex, toIndex); + byte[] vals = tmp.toArray(); + Arrays.sort(vals); + set(fromIndex, vals); + } + + /** {@inheritDoc} */ + public void fill(byte val) { + fill(0, size, val); + } + + /** {@inheritDoc} */ + public void fill(int fromIndex, int toIndex, byte val) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + + TByteLink l = getLinkAt(fromIndex); + if (toIndex > size) { + for (int i = fromIndex; i < size; i++) { + l.setValue(val); + l = l.getNext(); + } + for (int i = size; i < toIndex; i++) { + add(val); + } + } else { + for (int i = fromIndex; i < toIndex; i++) { + l.setValue(val); + l = l.getNext(); + } + } + + } + + /** {@inheritDoc} */ + public int binarySearch(byte value) { + return binarySearch(value, 0, size()); + } + + /** {@inheritDoc} */ + public int binarySearch(byte value, int fromIndex, int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + if (toIndex > size) { + throw new IndexOutOfBoundsException("end index > size: " + toIndex + " > " + size); + } + + + if (toIndex < fromIndex) { + return -(fromIndex+1); + } + + TByteLink middle; + int mid; + int from = fromIndex; + TByteLink fromLink = getLinkAt(fromIndex); + int to = toIndex; + + while (from < to) { + mid = (from + to) >>> 1; + middle = getLink(fromLink, from, mid); + if (middle.getValue() == value) + return mid; + + if (middle.getValue() < value) { + from = mid + 1; + fromLink = middle.next; + } else { + to = mid - 1; + } + } + + return -(from + 1); + } + + /** {@inheritDoc} */ + public int indexOf(byte value) { + return indexOf(0, value); + } + + /** {@inheritDoc} */ + public int indexOf(int offset, byte value) { + int count = offset; + + TByteLink l; + for (l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + return count; + + count++; + } + + if ( l != null && l.getValue() == value ) return count; + + return -1; + } + + /** {@inheritDoc} */ + public int lastIndexOf(byte value) { + return lastIndexOf(0, value); + } + + /** {@inheritDoc} */ + public int lastIndexOf(int offset, byte value) { + if (isEmpty()) + return -1; + + int last = -1; + int count = offset; + for (TByteLink l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + last = count; + + count++; + } + + return last; + } + + /** {@inheritDoc} */ + public boolean contains(byte value) { + if (isEmpty()) + return false; + + for (TByteLink l = head; got(l); l = l.getNext()) { + if (l.getValue() == value) + return true; + } + return false; + + } + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteIterator() { + TByteLink l = head; + TByteLink current; + + public byte next() { + if (no(l)) + throw new NoSuchElementException(); + + byte ret = l.getValue(); + current = l; + l = l.getNext(); + + return ret; + } + + public boolean hasNext() { + return got(l); + } + + public void remove() { + if (current == null) + throw new IllegalStateException(); + + removeLink(current); + current = null; + } + }; + } + + /** {@inheritDoc} */ + public TByteList grep(TByteProcedure condition) { + TByteList ret = new TByteLinkedList(); + for (TByteLink l = head; got(l); l = l.getNext()) { + if (condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public TByteList inverseGrep(TByteProcedure condition) { + TByteList ret = new TByteLinkedList(); + for (TByteLink l = head; got(l); l = l.getNext()) { + if (!condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public byte max() { + byte ret = Byte.MIN_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TByteLink l = head; got(l); l = l.getNext()) { + if (ret < l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public byte min() { + byte ret = Byte.MAX_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TByteLink l = head; got(l); l = l.getNext()) { + if (ret > l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public byte sum() { + byte sum = 0; + + for (TByteLink l = head; got(l); l = l.getNext()) { + sum += l.getValue(); + } + + return sum; + } + + // + // + // + static class TByteLink { + byte value; + TByteLink previous; + TByteLink next; + + TByteLink(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } + + public void setValue(byte value) { + this.value = value; + } + + public TByteLink getPrevious() { + return previous; + } + + public void setPrevious(TByteLink previous) { + this.previous = previous; + } + + public TByteLink getNext() { + return next; + } + + public void setNext(TByteLink next) { + this.next = next; + } + } + + class RemoveProcedure implements TByteProcedure { + boolean changed = false; + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(byte value) { + if (remove(value)) + changed = true; + + return true; + } + + public boolean isChanged() { + return changed; + } + } + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // NO_ENTRY_VALUE + out.writeByte(no_entry_value); + + // ENTRIES + out.writeInt(size); + for (TByteIterator iterator = iterator(); iterator.hasNext();) { + byte next = iterator.next(); + out.writeByte(next); + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + + // ENTRIES + int len = in.readInt(); + for (int i = 0; i < len; i++) { + add(in.readByte()); + } + } + + static boolean got(Object ref) { + return ref != null; + } + + static boolean no(Object ref) { + return ref == null; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TByteList ) ) return false; + + TByteList that = ( TByteList )other; + if ( size() != that.size() ) return false; + + for( int i = 0; i < size(); i++ ) { + if ( get( i ) != that.get( i ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = size(); i-- > 0; ) { + h += HashFunctions.hash( get( i ) ); + } + return h; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + TByteIterator it = iterator(); + while (it.hasNext()) { + byte next = it.next(); + buf.append(next); + if (it.hasNext()) + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + + } +} // TByteLinkedList diff --git a/src/gnu/trove/list/linked/TCharLinkedList.java b/src/gnu/trove/list/linked/TCharLinkedList.java new file mode 100644 index 0000000..ae2aab7 --- /dev/null +++ b/src/gnu/trove/list/linked/TCharLinkedList.java @@ -0,0 +1,1059 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// Copyright (c) 2011, Johan Parent All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.linked; + +import gnu.trove.function.TCharFunction; +import gnu.trove.list.TCharList; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.TCharCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, double linked list of char primitives. + */ +public class TCharLinkedList implements TCharList, Externalizable { + private char no_entry_value; + private int size; + + private TCharLink head = null; + private TCharLink tail = head; + + public TCharLinkedList() { + this( Constants.DEFAULT_CHAR_NO_ENTRY_VALUE ); + } + + public TCharLinkedList(char no_entry_value) { + this.no_entry_value = no_entry_value; + } + + public TCharLinkedList(TCharList list) { + no_entry_value = list.getNoEntryValue(); + // + for (TCharIterator iterator = list.iterator(); iterator.hasNext();) { + char next = iterator.next(); + add(next); + } + } + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + public boolean add(char val) { + TCharLink l = new TCharLink(val); + if (no(head)) { + head = l; + tail = l; + } else { + l.setPrevious(tail); + tail.setNext(l); + // + tail = l; + } + + size++; + return true; + } + + /** {@inheritDoc} */ + public void add(char[] vals) { + for (char val : vals) { + add(val); + } + } + + /** {@inheritDoc} */ + public void add(char[] vals, int offset, int length) { + for (int i = 0; i < length; i++) { + char val = vals[offset + i]; + add(val); + } + } + + /** {@inheritDoc} */ + public void insert(int offset, char value) { + TCharLinkedList tmp = new TCharLinkedList(); + tmp.add(value); + insert(offset, tmp); + } + + /** {@inheritDoc} */ + public void insert(int offset, char[] values) { + insert(offset, link(values, 0, values.length)); + } + + /** {@inheritDoc} */ + public void insert(int offset, char[] values, int valOffset, int len) { + insert(offset, link(values, valOffset, len)); + } + + void insert(int offset, TCharLinkedList tmp) { + TCharLink l = getLinkAt(offset); + + size = size + tmp.size; + // + if (l == head) { + // Add in front + tmp.tail.setNext(head); + head.setPrevious(tmp.tail); + head = tmp.head; + + return; + } + + if (no(l)) { + if (size == 0) { + // New empty list + head = tmp.head; + tail = tmp.tail; + } else { + // append + tail.setNext(tmp.head); + tmp.head.setPrevious(tail); + tail = tmp.tail; + } + } else { + TCharLink prev = l.getPrevious(); + l.getPrevious().setNext(tmp.head); + + // Link by behind tmp + tmp.tail.setNext(l); + l.setPrevious(tmp.tail); + + tmp.head.setPrevious(prev); + } + } + + static TCharLinkedList link(char[] values, int valOffset, int len) { + TCharLinkedList ret = new TCharLinkedList(); + + for (int i = 0; i < len; i++) { + ret.add(values[valOffset + i]); + } + + return ret; + } + + /** {@inheritDoc} */ + public char get(int offset) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TCharLink l = getLinkAt(offset); + // + if (no(l)) + return no_entry_value; + + return l.getValue(); + } + + /** + * Returns the link at the given offset. + *

+ * A simple bisection criteria is used to keep the worst case complexity equal to + * O(n/2) where n = size(). Simply start from head of list or tail depending on offset + * and list size. + * + * @param offset of the link + * @return link or null if non-existent + */ + public TCharLink getLinkAt(int offset) { + if (offset >= size()) + return null; + + if (offset <= (size() >>> 1)) + return getLink(head, 0, offset, true); + else + return getLink(tail, size() - 1, offset, false); + } + + /** + * Returns the link at absolute offset starting from given the initial link 'l' at index 'idx' + * + * @param l + * @param idx + * @param offset + * @return + */ + private static TCharLink getLink(TCharLink l, int idx, int offset) { + return getLink(l, idx, offset, true); + } + + /** + * Returns link at given absolute offset starting from link 'l' at index 'idx' + * @param l + * @param idx + * @param offset + * @param next + * @return + */ + private static TCharLink getLink(TCharLink l, int idx, int offset, boolean next) { + int i = idx; + // + while (got(l)) { + if (i == offset) { + return l; + } + + i = i + (next ? 1 : -1); + l = next ? l.getNext() : l.getPrevious(); + } + + return null; + } + + + /** {@inheritDoc} */ + public char set(int offset, char val) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TCharLink l = getLinkAt(offset); + // + if (no(l)) + throw new IndexOutOfBoundsException("at offset " + offset); + + char prev = l.getValue(); + l.setValue(val); + return prev; + } + + /** {@inheritDoc} */ + public void set(int offset, char[] values) { + set(offset, values, 0, values.length); + } + + /** {@inheritDoc} */ + public void set(int offset, char[] values, int valOffset, int length) { + for (int i = 0; i < length; i++) { + char value = values[valOffset + i]; + set(offset + i, value); + } + } + + /** {@inheritDoc} */ + public char replace(int offset, char val) { + return set(offset, val); + } + + /** {@inheritDoc} */ + public void clear() { + size = 0; + // + head = null; + tail = null; + } + + /** {@inheritDoc} */ + public boolean remove(char value) { + boolean changed = false; + for (TCharLink l = head; got(l); l = l.getNext()) { + // + if (l.getValue() == value) { + changed = true; + // + removeLink(l); + } + } + + return changed; + } + + /** + * unlinks the give TCharLink from the list + * + * @param l + */ + private void removeLink(TCharLink l) { + if (no(l)) + return; + + size--; + + TCharLink prev = l.getPrevious(); + TCharLink next = l.getNext(); + + if (got(prev)) { + prev.setNext(next); + } else { + // No previous we must be head + head = next; + } + + if (got(next)) { + next.setPrevious(prev); + } else { + // No next so me must be tail + tail = prev; + } + // Unlink + l.setNext(null); + l.setPrevious(null); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + if (isEmpty()) + return false; + + for (Object o : collection) { + if (o instanceof Character) { + Character i = (Character) o; + if (!(contains(i))) + return false; + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(TCharCollection collection) { + if (isEmpty()) + return false; + + for (TCharIterator it = collection.iterator(); it.hasNext();) { + char i = it.next(); + if (!(contains(i))) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(char[] array) { + if (isEmpty()) + return false; + + for (char i : array) { + if (!contains(i)) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + boolean ret = false; + for (Character v : collection) { + if (add(v.charValue())) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(TCharCollection collection) { + boolean ret = false; + for (TCharIterator it = collection.iterator(); it.hasNext();) { + char i = it.next(); + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(char[] array) { + boolean ret = false; + for (char i : array) { + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + boolean modified = false; + TCharIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(Character.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(TCharCollection collection) { + boolean modified = false; + TCharIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(char[] array) { + Arrays.sort(array); + + boolean modified = false; + TCharIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) < 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + boolean modified = false; + TCharIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(Character.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(TCharCollection collection) { + boolean modified = false; + TCharIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(char[] array) { + Arrays.sort(array); + + boolean modified = false; + TCharIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) >= 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public char removeAt(int offset) { + TCharLink l = getLinkAt(offset); + if (no(l)) + throw new ArrayIndexOutOfBoundsException("no elemenet at " + offset); + + char prev = l.getValue(); + removeLink(l); + return prev; + } + + /** {@inheritDoc} */ + public void remove(int offset, int length) { + for (int i = 0; i < length; i++) { + removeAt(offset); // since the list shrinks we don't need to use offset+i to get the next entry ;) + } + } + + /** {@inheritDoc} */ + public void transformValues(TCharFunction function) { + for (TCharLink l = head; got(l);) { + // + l.setValue(function.execute(l.getValue())); + // + l = l.getNext(); + } + } + + /** {@inheritDoc} */ + public void reverse() { + TCharLink h = head; + TCharLink t = tail; + TCharLink prev, next, tmp; + + // + TCharLink l = head; + while (got(l)) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // + head = t; + tail = h; + } + + /** {@inheritDoc} */ + public void reverse(int from, int to) { + if (from > to) + throw new IllegalArgumentException("from > to : " + from + ">" + to); + + TCharLink start = getLinkAt(from); + TCharLink stop = getLinkAt(to); + TCharLink prev, next; + TCharLink tmp = null; + + TCharLink tmpHead = start.getPrevious(); + + // + TCharLink l = start; + while (l != stop) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // At this point l == stop and tmp is the but last element { + if (got(tmp)) { + tmpHead.setNext(tmp); + stop.setPrevious(tmpHead); + } + start.setNext(stop); + stop.setPrevious(start); + } + + /** {@inheritDoc} */ + public void shuffle(Random rand) { + for (int i = 0; i < size; i++) { + TCharLink l = getLinkAt(rand.nextInt(size())); + removeLink(l); + add(l.getValue()); + } + } + + /** {@inheritDoc} */ + public TCharList subList(int begin, int end) { + if (end < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than end index " + end); + } + if (size < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than last index " + size); + } + if (begin < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + if (end > size) { + throw new IndexOutOfBoundsException("end index < " + size); + } + + TCharLinkedList ret = new TCharLinkedList(); + TCharLink tmp = getLinkAt(begin); + for (int i = begin; i < end; i++) { + ret.add(tmp.getValue()); // copy + tmp = tmp.getNext(); + } + + return ret; + } + + /** {@inheritDoc} */ + public char[] toArray() { + return toArray(new char[size], 0, size); + } + + /** {@inheritDoc} */ + public char[] toArray(int offset, int len) { + return toArray(new char[len], offset, 0, len); + } + + /** {@inheritDoc} */ + public char[] toArray(char[] dest) { + return toArray(dest, 0, size); + } + + /** {@inheritDoc} */ + public char[] toArray(char[] dest, int offset, int len) { + return toArray(dest, offset, 0, len); + } + + /** {@inheritDoc} */ + public char[] toArray(char[] dest, int source_pos, int dest_pos, int len) { + if (len == 0) { + return dest; // nothing to copy + } + if (source_pos < 0 || source_pos >= size()) { + throw new ArrayIndexOutOfBoundsException(source_pos); + } + + TCharLink tmp = getLinkAt(source_pos); + for (int i = 0; i < len; i++) { + dest[dest_pos + i] = tmp.getValue(); // copy + tmp = tmp.getNext(); + } + + return dest; + } + + /** {@inheritDoc} */ + public boolean forEach(TCharProcedure procedure) { + for (TCharLink l = head; got(l); l = l.getNext()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean forEachDescending(TCharProcedure procedure) { + for (TCharLink l = tail; got(l); l = l.getPrevious()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public void sort() { + sort(0, size); + } + + /** {@inheritDoc} */ + public void sort(int fromIndex, int toIndex) { + TCharList tmp = subList(fromIndex, toIndex); + char[] vals = tmp.toArray(); + Arrays.sort(vals); + set(fromIndex, vals); + } + + /** {@inheritDoc} */ + public void fill(char val) { + fill(0, size, val); + } + + /** {@inheritDoc} */ + public void fill(int fromIndex, int toIndex, char val) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + + TCharLink l = getLinkAt(fromIndex); + if (toIndex > size) { + for (int i = fromIndex; i < size; i++) { + l.setValue(val); + l = l.getNext(); + } + for (int i = size; i < toIndex; i++) { + add(val); + } + } else { + for (int i = fromIndex; i < toIndex; i++) { + l.setValue(val); + l = l.getNext(); + } + } + + } + + /** {@inheritDoc} */ + public int binarySearch(char value) { + return binarySearch(value, 0, size()); + } + + /** {@inheritDoc} */ + public int binarySearch(char value, int fromIndex, int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + if (toIndex > size) { + throw new IndexOutOfBoundsException("end index > size: " + toIndex + " > " + size); + } + + + if (toIndex < fromIndex) { + return -(fromIndex+1); + } + + TCharLink middle; + int mid; + int from = fromIndex; + TCharLink fromLink = getLinkAt(fromIndex); + int to = toIndex; + + while (from < to) { + mid = (from + to) >>> 1; + middle = getLink(fromLink, from, mid); + if (middle.getValue() == value) + return mid; + + if (middle.getValue() < value) { + from = mid + 1; + fromLink = middle.next; + } else { + to = mid - 1; + } + } + + return -(from + 1); + } + + /** {@inheritDoc} */ + public int indexOf(char value) { + return indexOf(0, value); + } + + /** {@inheritDoc} */ + public int indexOf(int offset, char value) { + int count = offset; + + TCharLink l; + for (l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + return count; + + count++; + } + + if ( l != null && l.getValue() == value ) return count; + + return -1; + } + + /** {@inheritDoc} */ + public int lastIndexOf(char value) { + return lastIndexOf(0, value); + } + + /** {@inheritDoc} */ + public int lastIndexOf(int offset, char value) { + if (isEmpty()) + return -1; + + int last = -1; + int count = offset; + for (TCharLink l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + last = count; + + count++; + } + + return last; + } + + /** {@inheritDoc} */ + public boolean contains(char value) { + if (isEmpty()) + return false; + + for (TCharLink l = head; got(l); l = l.getNext()) { + if (l.getValue() == value) + return true; + } + return false; + + } + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharIterator() { + TCharLink l = head; + TCharLink current; + + public char next() { + if (no(l)) + throw new NoSuchElementException(); + + char ret = l.getValue(); + current = l; + l = l.getNext(); + + return ret; + } + + public boolean hasNext() { + return got(l); + } + + public void remove() { + if (current == null) + throw new IllegalStateException(); + + removeLink(current); + current = null; + } + }; + } + + /** {@inheritDoc} */ + public TCharList grep(TCharProcedure condition) { + TCharList ret = new TCharLinkedList(); + for (TCharLink l = head; got(l); l = l.getNext()) { + if (condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public TCharList inverseGrep(TCharProcedure condition) { + TCharList ret = new TCharLinkedList(); + for (TCharLink l = head; got(l); l = l.getNext()) { + if (!condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public char max() { + char ret = Character.MIN_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TCharLink l = head; got(l); l = l.getNext()) { + if (ret < l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public char min() { + char ret = Character.MAX_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TCharLink l = head; got(l); l = l.getNext()) { + if (ret > l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public char sum() { + char sum = 0; + + for (TCharLink l = head; got(l); l = l.getNext()) { + sum += l.getValue(); + } + + return sum; + } + + // + // + // + static class TCharLink { + char value; + TCharLink previous; + TCharLink next; + + TCharLink(char value) { + this.value = value; + } + + public char getValue() { + return value; + } + + public void setValue(char value) { + this.value = value; + } + + public TCharLink getPrevious() { + return previous; + } + + public void setPrevious(TCharLink previous) { + this.previous = previous; + } + + public TCharLink getNext() { + return next; + } + + public void setNext(TCharLink next) { + this.next = next; + } + } + + class RemoveProcedure implements TCharProcedure { + boolean changed = false; + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(char value) { + if (remove(value)) + changed = true; + + return true; + } + + public boolean isChanged() { + return changed; + } + } + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // NO_ENTRY_VALUE + out.writeChar(no_entry_value); + + // ENTRIES + out.writeInt(size); + for (TCharIterator iterator = iterator(); iterator.hasNext();) { + char next = iterator.next(); + out.writeChar(next); + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + + // ENTRIES + int len = in.readInt(); + for (int i = 0; i < len; i++) { + add(in.readChar()); + } + } + + static boolean got(Object ref) { + return ref != null; + } + + static boolean no(Object ref) { + return ref == null; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TCharList ) ) return false; + + TCharList that = ( TCharList )other; + if ( size() != that.size() ) return false; + + for( int i = 0; i < size(); i++ ) { + if ( get( i ) != that.get( i ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = size(); i-- > 0; ) { + h += HashFunctions.hash( get( i ) ); + } + return h; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + TCharIterator it = iterator(); + while (it.hasNext()) { + char next = it.next(); + buf.append(next); + if (it.hasNext()) + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + + } +} // TCharLinkedList diff --git a/src/gnu/trove/list/linked/TDoubleLinkedList.java b/src/gnu/trove/list/linked/TDoubleLinkedList.java new file mode 100644 index 0000000..5b42d15 --- /dev/null +++ b/src/gnu/trove/list/linked/TDoubleLinkedList.java @@ -0,0 +1,1059 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// Copyright (c) 2011, Johan Parent All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.linked; + +import gnu.trove.function.TDoubleFunction; +import gnu.trove.list.TDoubleList; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.TDoubleCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, double linked list of double primitives. + */ +public class TDoubleLinkedList implements TDoubleList, Externalizable { + private double no_entry_value; + private int size; + + private TDoubleLink head = null; + private TDoubleLink tail = head; + + public TDoubleLinkedList() { + this( Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE ); + } + + public TDoubleLinkedList(double no_entry_value) { + this.no_entry_value = no_entry_value; + } + + public TDoubleLinkedList(TDoubleList list) { + no_entry_value = list.getNoEntryValue(); + // + for (TDoubleIterator iterator = list.iterator(); iterator.hasNext();) { + double next = iterator.next(); + add(next); + } + } + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + public boolean add(double val) { + TDoubleLink l = new TDoubleLink(val); + if (no(head)) { + head = l; + tail = l; + } else { + l.setPrevious(tail); + tail.setNext(l); + // + tail = l; + } + + size++; + return true; + } + + /** {@inheritDoc} */ + public void add(double[] vals) { + for (double val : vals) { + add(val); + } + } + + /** {@inheritDoc} */ + public void add(double[] vals, int offset, int length) { + for (int i = 0; i < length; i++) { + double val = vals[offset + i]; + add(val); + } + } + + /** {@inheritDoc} */ + public void insert(int offset, double value) { + TDoubleLinkedList tmp = new TDoubleLinkedList(); + tmp.add(value); + insert(offset, tmp); + } + + /** {@inheritDoc} */ + public void insert(int offset, double[] values) { + insert(offset, link(values, 0, values.length)); + } + + /** {@inheritDoc} */ + public void insert(int offset, double[] values, int valOffset, int len) { + insert(offset, link(values, valOffset, len)); + } + + void insert(int offset, TDoubleLinkedList tmp) { + TDoubleLink l = getLinkAt(offset); + + size = size + tmp.size; + // + if (l == head) { + // Add in front + tmp.tail.setNext(head); + head.setPrevious(tmp.tail); + head = tmp.head; + + return; + } + + if (no(l)) { + if (size == 0) { + // New empty list + head = tmp.head; + tail = tmp.tail; + } else { + // append + tail.setNext(tmp.head); + tmp.head.setPrevious(tail); + tail = tmp.tail; + } + } else { + TDoubleLink prev = l.getPrevious(); + l.getPrevious().setNext(tmp.head); + + // Link by behind tmp + tmp.tail.setNext(l); + l.setPrevious(tmp.tail); + + tmp.head.setPrevious(prev); + } + } + + static TDoubleLinkedList link(double[] values, int valOffset, int len) { + TDoubleLinkedList ret = new TDoubleLinkedList(); + + for (int i = 0; i < len; i++) { + ret.add(values[valOffset + i]); + } + + return ret; + } + + /** {@inheritDoc} */ + public double get(int offset) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TDoubleLink l = getLinkAt(offset); + // + if (no(l)) + return no_entry_value; + + return l.getValue(); + } + + /** + * Returns the link at the given offset. + *

+ * A simple bisection criteria is used to keep the worst case complexity equal to + * O(n/2) where n = size(). Simply start from head of list or tail depending on offset + * and list size. + * + * @param offset of the link + * @return link or null if non-existent + */ + public TDoubleLink getLinkAt(int offset) { + if (offset >= size()) + return null; + + if (offset <= (size() >>> 1)) + return getLink(head, 0, offset, true); + else + return getLink(tail, size() - 1, offset, false); + } + + /** + * Returns the link at absolute offset starting from given the initial link 'l' at index 'idx' + * + * @param l + * @param idx + * @param offset + * @return + */ + private static TDoubleLink getLink(TDoubleLink l, int idx, int offset) { + return getLink(l, idx, offset, true); + } + + /** + * Returns link at given absolute offset starting from link 'l' at index 'idx' + * @param l + * @param idx + * @param offset + * @param next + * @return + */ + private static TDoubleLink getLink(TDoubleLink l, int idx, int offset, boolean next) { + int i = idx; + // + while (got(l)) { + if (i == offset) { + return l; + } + + i = i + (next ? 1 : -1); + l = next ? l.getNext() : l.getPrevious(); + } + + return null; + } + + + /** {@inheritDoc} */ + public double set(int offset, double val) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TDoubleLink l = getLinkAt(offset); + // + if (no(l)) + throw new IndexOutOfBoundsException("at offset " + offset); + + double prev = l.getValue(); + l.setValue(val); + return prev; + } + + /** {@inheritDoc} */ + public void set(int offset, double[] values) { + set(offset, values, 0, values.length); + } + + /** {@inheritDoc} */ + public void set(int offset, double[] values, int valOffset, int length) { + for (int i = 0; i < length; i++) { + double value = values[valOffset + i]; + set(offset + i, value); + } + } + + /** {@inheritDoc} */ + public double replace(int offset, double val) { + return set(offset, val); + } + + /** {@inheritDoc} */ + public void clear() { + size = 0; + // + head = null; + tail = null; + } + + /** {@inheritDoc} */ + public boolean remove(double value) { + boolean changed = false; + for (TDoubleLink l = head; got(l); l = l.getNext()) { + // + if (l.getValue() == value) { + changed = true; + // + removeLink(l); + } + } + + return changed; + } + + /** + * unlinks the give TDoubleLink from the list + * + * @param l + */ + private void removeLink(TDoubleLink l) { + if (no(l)) + return; + + size--; + + TDoubleLink prev = l.getPrevious(); + TDoubleLink next = l.getNext(); + + if (got(prev)) { + prev.setNext(next); + } else { + // No previous we must be head + head = next; + } + + if (got(next)) { + next.setPrevious(prev); + } else { + // No next so me must be tail + tail = prev; + } + // Unlink + l.setNext(null); + l.setPrevious(null); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + if (isEmpty()) + return false; + + for (Object o : collection) { + if (o instanceof Double) { + Double i = (Double) o; + if (!(contains(i))) + return false; + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(TDoubleCollection collection) { + if (isEmpty()) + return false; + + for (TDoubleIterator it = collection.iterator(); it.hasNext();) { + double i = it.next(); + if (!(contains(i))) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(double[] array) { + if (isEmpty()) + return false; + + for (double i : array) { + if (!contains(i)) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + boolean ret = false; + for (Double v : collection) { + if (add(v.doubleValue())) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(TDoubleCollection collection) { + boolean ret = false; + for (TDoubleIterator it = collection.iterator(); it.hasNext();) { + double i = it.next(); + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(double[] array) { + boolean ret = false; + for (double i : array) { + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(Double.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(TDoubleCollection collection) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(double[] array) { + Arrays.sort(array); + + boolean modified = false; + TDoubleIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) < 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(Double.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(TDoubleCollection collection) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(double[] array) { + Arrays.sort(array); + + boolean modified = false; + TDoubleIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) >= 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public double removeAt(int offset) { + TDoubleLink l = getLinkAt(offset); + if (no(l)) + throw new ArrayIndexOutOfBoundsException("no elemenet at " + offset); + + double prev = l.getValue(); + removeLink(l); + return prev; + } + + /** {@inheritDoc} */ + public void remove(int offset, int length) { + for (int i = 0; i < length; i++) { + removeAt(offset); // since the list shrinks we don't need to use offset+i to get the next entry ;) + } + } + + /** {@inheritDoc} */ + public void transformValues(TDoubleFunction function) { + for (TDoubleLink l = head; got(l);) { + // + l.setValue(function.execute(l.getValue())); + // + l = l.getNext(); + } + } + + /** {@inheritDoc} */ + public void reverse() { + TDoubleLink h = head; + TDoubleLink t = tail; + TDoubleLink prev, next, tmp; + + // + TDoubleLink l = head; + while (got(l)) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // + head = t; + tail = h; + } + + /** {@inheritDoc} */ + public void reverse(int from, int to) { + if (from > to) + throw new IllegalArgumentException("from > to : " + from + ">" + to); + + TDoubleLink start = getLinkAt(from); + TDoubleLink stop = getLinkAt(to); + TDoubleLink prev, next; + TDoubleLink tmp = null; + + TDoubleLink tmpHead = start.getPrevious(); + + // + TDoubleLink l = start; + while (l != stop) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // At this point l == stop and tmp is the but last element { + if (got(tmp)) { + tmpHead.setNext(tmp); + stop.setPrevious(tmpHead); + } + start.setNext(stop); + stop.setPrevious(start); + } + + /** {@inheritDoc} */ + public void shuffle(Random rand) { + for (int i = 0; i < size; i++) { + TDoubleLink l = getLinkAt(rand.nextInt(size())); + removeLink(l); + add(l.getValue()); + } + } + + /** {@inheritDoc} */ + public TDoubleList subList(int begin, int end) { + if (end < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than end index " + end); + } + if (size < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than last index " + size); + } + if (begin < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + if (end > size) { + throw new IndexOutOfBoundsException("end index < " + size); + } + + TDoubleLinkedList ret = new TDoubleLinkedList(); + TDoubleLink tmp = getLinkAt(begin); + for (int i = begin; i < end; i++) { + ret.add(tmp.getValue()); // copy + tmp = tmp.getNext(); + } + + return ret; + } + + /** {@inheritDoc} */ + public double[] toArray() { + return toArray(new double[size], 0, size); + } + + /** {@inheritDoc} */ + public double[] toArray(int offset, int len) { + return toArray(new double[len], offset, 0, len); + } + + /** {@inheritDoc} */ + public double[] toArray(double[] dest) { + return toArray(dest, 0, size); + } + + /** {@inheritDoc} */ + public double[] toArray(double[] dest, int offset, int len) { + return toArray(dest, offset, 0, len); + } + + /** {@inheritDoc} */ + public double[] toArray(double[] dest, int source_pos, int dest_pos, int len) { + if (len == 0) { + return dest; // nothing to copy + } + if (source_pos < 0 || source_pos >= size()) { + throw new ArrayIndexOutOfBoundsException(source_pos); + } + + TDoubleLink tmp = getLinkAt(source_pos); + for (int i = 0; i < len; i++) { + dest[dest_pos + i] = tmp.getValue(); // copy + tmp = tmp.getNext(); + } + + return dest; + } + + /** {@inheritDoc} */ + public boolean forEach(TDoubleProcedure procedure) { + for (TDoubleLink l = head; got(l); l = l.getNext()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean forEachDescending(TDoubleProcedure procedure) { + for (TDoubleLink l = tail; got(l); l = l.getPrevious()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public void sort() { + sort(0, size); + } + + /** {@inheritDoc} */ + public void sort(int fromIndex, int toIndex) { + TDoubleList tmp = subList(fromIndex, toIndex); + double[] vals = tmp.toArray(); + Arrays.sort(vals); + set(fromIndex, vals); + } + + /** {@inheritDoc} */ + public void fill(double val) { + fill(0, size, val); + } + + /** {@inheritDoc} */ + public void fill(int fromIndex, int toIndex, double val) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + + TDoubleLink l = getLinkAt(fromIndex); + if (toIndex > size) { + for (int i = fromIndex; i < size; i++) { + l.setValue(val); + l = l.getNext(); + } + for (int i = size; i < toIndex; i++) { + add(val); + } + } else { + for (int i = fromIndex; i < toIndex; i++) { + l.setValue(val); + l = l.getNext(); + } + } + + } + + /** {@inheritDoc} */ + public int binarySearch(double value) { + return binarySearch(value, 0, size()); + } + + /** {@inheritDoc} */ + public int binarySearch(double value, int fromIndex, int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + if (toIndex > size) { + throw new IndexOutOfBoundsException("end index > size: " + toIndex + " > " + size); + } + + + if (toIndex < fromIndex) { + return -(fromIndex+1); + } + + TDoubleLink middle; + int mid; + int from = fromIndex; + TDoubleLink fromLink = getLinkAt(fromIndex); + int to = toIndex; + + while (from < to) { + mid = (from + to) >>> 1; + middle = getLink(fromLink, from, mid); + if (middle.getValue() == value) + return mid; + + if (middle.getValue() < value) { + from = mid + 1; + fromLink = middle.next; + } else { + to = mid - 1; + } + } + + return -(from + 1); + } + + /** {@inheritDoc} */ + public int indexOf(double value) { + return indexOf(0, value); + } + + /** {@inheritDoc} */ + public int indexOf(int offset, double value) { + int count = offset; + + TDoubleLink l; + for (l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + return count; + + count++; + } + + if ( l != null && l.getValue() == value ) return count; + + return -1; + } + + /** {@inheritDoc} */ + public int lastIndexOf(double value) { + return lastIndexOf(0, value); + } + + /** {@inheritDoc} */ + public int lastIndexOf(int offset, double value) { + if (isEmpty()) + return -1; + + int last = -1; + int count = offset; + for (TDoubleLink l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + last = count; + + count++; + } + + return last; + } + + /** {@inheritDoc} */ + public boolean contains(double value) { + if (isEmpty()) + return false; + + for (TDoubleLink l = head; got(l); l = l.getNext()) { + if (l.getValue() == value) + return true; + } + return false; + + } + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleIterator() { + TDoubleLink l = head; + TDoubleLink current; + + public double next() { + if (no(l)) + throw new NoSuchElementException(); + + double ret = l.getValue(); + current = l; + l = l.getNext(); + + return ret; + } + + public boolean hasNext() { + return got(l); + } + + public void remove() { + if (current == null) + throw new IllegalStateException(); + + removeLink(current); + current = null; + } + }; + } + + /** {@inheritDoc} */ + public TDoubleList grep(TDoubleProcedure condition) { + TDoubleList ret = new TDoubleLinkedList(); + for (TDoubleLink l = head; got(l); l = l.getNext()) { + if (condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public TDoubleList inverseGrep(TDoubleProcedure condition) { + TDoubleList ret = new TDoubleLinkedList(); + for (TDoubleLink l = head; got(l); l = l.getNext()) { + if (!condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public double max() { + double ret = Double.NEGATIVE_INFINITY; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TDoubleLink l = head; got(l); l = l.getNext()) { + if (ret < l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public double min() { + double ret = Double.POSITIVE_INFINITY; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TDoubleLink l = head; got(l); l = l.getNext()) { + if (ret > l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public double sum() { + double sum = 0; + + for (TDoubleLink l = head; got(l); l = l.getNext()) { + sum += l.getValue(); + } + + return sum; + } + + // + // + // + static class TDoubleLink { + double value; + TDoubleLink previous; + TDoubleLink next; + + TDoubleLink(double value) { + this.value = value; + } + + public double getValue() { + return value; + } + + public void setValue(double value) { + this.value = value; + } + + public TDoubleLink getPrevious() { + return previous; + } + + public void setPrevious(TDoubleLink previous) { + this.previous = previous; + } + + public TDoubleLink getNext() { + return next; + } + + public void setNext(TDoubleLink next) { + this.next = next; + } + } + + class RemoveProcedure implements TDoubleProcedure { + boolean changed = false; + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(double value) { + if (remove(value)) + changed = true; + + return true; + } + + public boolean isChanged() { + return changed; + } + } + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // NO_ENTRY_VALUE + out.writeDouble(no_entry_value); + + // ENTRIES + out.writeInt(size); + for (TDoubleIterator iterator = iterator(); iterator.hasNext();) { + double next = iterator.next(); + out.writeDouble(next); + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + + // ENTRIES + int len = in.readInt(); + for (int i = 0; i < len; i++) { + add(in.readDouble()); + } + } + + static boolean got(Object ref) { + return ref != null; + } + + static boolean no(Object ref) { + return ref == null; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TDoubleList ) ) return false; + + TDoubleList that = ( TDoubleList )other; + if ( size() != that.size() ) return false; + + for( int i = 0; i < size(); i++ ) { + if ( get( i ) != that.get( i ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = size(); i-- > 0; ) { + h += HashFunctions.hash( get( i ) ); + } + return h; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + TDoubleIterator it = iterator(); + while (it.hasNext()) { + double next = it.next(); + buf.append(next); + if (it.hasNext()) + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + + } +} // TDoubleLinkedList diff --git a/src/gnu/trove/list/linked/TFloatLinkedList.java b/src/gnu/trove/list/linked/TFloatLinkedList.java new file mode 100644 index 0000000..0de7cee --- /dev/null +++ b/src/gnu/trove/list/linked/TFloatLinkedList.java @@ -0,0 +1,1059 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// Copyright (c) 2011, Johan Parent All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.linked; + +import gnu.trove.function.TFloatFunction; +import gnu.trove.list.TFloatList; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.TFloatCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, double linked list of float primitives. + */ +public class TFloatLinkedList implements TFloatList, Externalizable { + private float no_entry_value; + private int size; + + private TFloatLink head = null; + private TFloatLink tail = head; + + public TFloatLinkedList() { + this( Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE ); + } + + public TFloatLinkedList(float no_entry_value) { + this.no_entry_value = no_entry_value; + } + + public TFloatLinkedList(TFloatList list) { + no_entry_value = list.getNoEntryValue(); + // + for (TFloatIterator iterator = list.iterator(); iterator.hasNext();) { + float next = iterator.next(); + add(next); + } + } + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + public boolean add(float val) { + TFloatLink l = new TFloatLink(val); + if (no(head)) { + head = l; + tail = l; + } else { + l.setPrevious(tail); + tail.setNext(l); + // + tail = l; + } + + size++; + return true; + } + + /** {@inheritDoc} */ + public void add(float[] vals) { + for (float val : vals) { + add(val); + } + } + + /** {@inheritDoc} */ + public void add(float[] vals, int offset, int length) { + for (int i = 0; i < length; i++) { + float val = vals[offset + i]; + add(val); + } + } + + /** {@inheritDoc} */ + public void insert(int offset, float value) { + TFloatLinkedList tmp = new TFloatLinkedList(); + tmp.add(value); + insert(offset, tmp); + } + + /** {@inheritDoc} */ + public void insert(int offset, float[] values) { + insert(offset, link(values, 0, values.length)); + } + + /** {@inheritDoc} */ + public void insert(int offset, float[] values, int valOffset, int len) { + insert(offset, link(values, valOffset, len)); + } + + void insert(int offset, TFloatLinkedList tmp) { + TFloatLink l = getLinkAt(offset); + + size = size + tmp.size; + // + if (l == head) { + // Add in front + tmp.tail.setNext(head); + head.setPrevious(tmp.tail); + head = tmp.head; + + return; + } + + if (no(l)) { + if (size == 0) { + // New empty list + head = tmp.head; + tail = tmp.tail; + } else { + // append + tail.setNext(tmp.head); + tmp.head.setPrevious(tail); + tail = tmp.tail; + } + } else { + TFloatLink prev = l.getPrevious(); + l.getPrevious().setNext(tmp.head); + + // Link by behind tmp + tmp.tail.setNext(l); + l.setPrevious(tmp.tail); + + tmp.head.setPrevious(prev); + } + } + + static TFloatLinkedList link(float[] values, int valOffset, int len) { + TFloatLinkedList ret = new TFloatLinkedList(); + + for (int i = 0; i < len; i++) { + ret.add(values[valOffset + i]); + } + + return ret; + } + + /** {@inheritDoc} */ + public float get(int offset) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TFloatLink l = getLinkAt(offset); + // + if (no(l)) + return no_entry_value; + + return l.getValue(); + } + + /** + * Returns the link at the given offset. + *

+ * A simple bisection criteria is used to keep the worst case complexity equal to + * O(n/2) where n = size(). Simply start from head of list or tail depending on offset + * and list size. + * + * @param offset of the link + * @return link or null if non-existent + */ + public TFloatLink getLinkAt(int offset) { + if (offset >= size()) + return null; + + if (offset <= (size() >>> 1)) + return getLink(head, 0, offset, true); + else + return getLink(tail, size() - 1, offset, false); + } + + /** + * Returns the link at absolute offset starting from given the initial link 'l' at index 'idx' + * + * @param l + * @param idx + * @param offset + * @return + */ + private static TFloatLink getLink(TFloatLink l, int idx, int offset) { + return getLink(l, idx, offset, true); + } + + /** + * Returns link at given absolute offset starting from link 'l' at index 'idx' + * @param l + * @param idx + * @param offset + * @param next + * @return + */ + private static TFloatLink getLink(TFloatLink l, int idx, int offset, boolean next) { + int i = idx; + // + while (got(l)) { + if (i == offset) { + return l; + } + + i = i + (next ? 1 : -1); + l = next ? l.getNext() : l.getPrevious(); + } + + return null; + } + + + /** {@inheritDoc} */ + public float set(int offset, float val) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TFloatLink l = getLinkAt(offset); + // + if (no(l)) + throw new IndexOutOfBoundsException("at offset " + offset); + + float prev = l.getValue(); + l.setValue(val); + return prev; + } + + /** {@inheritDoc} */ + public void set(int offset, float[] values) { + set(offset, values, 0, values.length); + } + + /** {@inheritDoc} */ + public void set(int offset, float[] values, int valOffset, int length) { + for (int i = 0; i < length; i++) { + float value = values[valOffset + i]; + set(offset + i, value); + } + } + + /** {@inheritDoc} */ + public float replace(int offset, float val) { + return set(offset, val); + } + + /** {@inheritDoc} */ + public void clear() { + size = 0; + // + head = null; + tail = null; + } + + /** {@inheritDoc} */ + public boolean remove(float value) { + boolean changed = false; + for (TFloatLink l = head; got(l); l = l.getNext()) { + // + if (l.getValue() == value) { + changed = true; + // + removeLink(l); + } + } + + return changed; + } + + /** + * unlinks the give TFloatLink from the list + * + * @param l + */ + private void removeLink(TFloatLink l) { + if (no(l)) + return; + + size--; + + TFloatLink prev = l.getPrevious(); + TFloatLink next = l.getNext(); + + if (got(prev)) { + prev.setNext(next); + } else { + // No previous we must be head + head = next; + } + + if (got(next)) { + next.setPrevious(prev); + } else { + // No next so me must be tail + tail = prev; + } + // Unlink + l.setNext(null); + l.setPrevious(null); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + if (isEmpty()) + return false; + + for (Object o : collection) { + if (o instanceof Float) { + Float i = (Float) o; + if (!(contains(i))) + return false; + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(TFloatCollection collection) { + if (isEmpty()) + return false; + + for (TFloatIterator it = collection.iterator(); it.hasNext();) { + float i = it.next(); + if (!(contains(i))) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(float[] array) { + if (isEmpty()) + return false; + + for (float i : array) { + if (!contains(i)) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + boolean ret = false; + for (Float v : collection) { + if (add(v.floatValue())) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(TFloatCollection collection) { + boolean ret = false; + for (TFloatIterator it = collection.iterator(); it.hasNext();) { + float i = it.next(); + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(float[] array) { + boolean ret = false; + for (float i : array) { + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + boolean modified = false; + TFloatIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(Float.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(TFloatCollection collection) { + boolean modified = false; + TFloatIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(float[] array) { + Arrays.sort(array); + + boolean modified = false; + TFloatIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) < 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + boolean modified = false; + TFloatIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(Float.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(TFloatCollection collection) { + boolean modified = false; + TFloatIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(float[] array) { + Arrays.sort(array); + + boolean modified = false; + TFloatIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) >= 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public float removeAt(int offset) { + TFloatLink l = getLinkAt(offset); + if (no(l)) + throw new ArrayIndexOutOfBoundsException("no elemenet at " + offset); + + float prev = l.getValue(); + removeLink(l); + return prev; + } + + /** {@inheritDoc} */ + public void remove(int offset, int length) { + for (int i = 0; i < length; i++) { + removeAt(offset); // since the list shrinks we don't need to use offset+i to get the next entry ;) + } + } + + /** {@inheritDoc} */ + public void transformValues(TFloatFunction function) { + for (TFloatLink l = head; got(l);) { + // + l.setValue(function.execute(l.getValue())); + // + l = l.getNext(); + } + } + + /** {@inheritDoc} */ + public void reverse() { + TFloatLink h = head; + TFloatLink t = tail; + TFloatLink prev, next, tmp; + + // + TFloatLink l = head; + while (got(l)) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // + head = t; + tail = h; + } + + /** {@inheritDoc} */ + public void reverse(int from, int to) { + if (from > to) + throw new IllegalArgumentException("from > to : " + from + ">" + to); + + TFloatLink start = getLinkAt(from); + TFloatLink stop = getLinkAt(to); + TFloatLink prev, next; + TFloatLink tmp = null; + + TFloatLink tmpHead = start.getPrevious(); + + // + TFloatLink l = start; + while (l != stop) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // At this point l == stop and tmp is the but last element { + if (got(tmp)) { + tmpHead.setNext(tmp); + stop.setPrevious(tmpHead); + } + start.setNext(stop); + stop.setPrevious(start); + } + + /** {@inheritDoc} */ + public void shuffle(Random rand) { + for (int i = 0; i < size; i++) { + TFloatLink l = getLinkAt(rand.nextInt(size())); + removeLink(l); + add(l.getValue()); + } + } + + /** {@inheritDoc} */ + public TFloatList subList(int begin, int end) { + if (end < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than end index " + end); + } + if (size < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than last index " + size); + } + if (begin < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + if (end > size) { + throw new IndexOutOfBoundsException("end index < " + size); + } + + TFloatLinkedList ret = new TFloatLinkedList(); + TFloatLink tmp = getLinkAt(begin); + for (int i = begin; i < end; i++) { + ret.add(tmp.getValue()); // copy + tmp = tmp.getNext(); + } + + return ret; + } + + /** {@inheritDoc} */ + public float[] toArray() { + return toArray(new float[size], 0, size); + } + + /** {@inheritDoc} */ + public float[] toArray(int offset, int len) { + return toArray(new float[len], offset, 0, len); + } + + /** {@inheritDoc} */ + public float[] toArray(float[] dest) { + return toArray(dest, 0, size); + } + + /** {@inheritDoc} */ + public float[] toArray(float[] dest, int offset, int len) { + return toArray(dest, offset, 0, len); + } + + /** {@inheritDoc} */ + public float[] toArray(float[] dest, int source_pos, int dest_pos, int len) { + if (len == 0) { + return dest; // nothing to copy + } + if (source_pos < 0 || source_pos >= size()) { + throw new ArrayIndexOutOfBoundsException(source_pos); + } + + TFloatLink tmp = getLinkAt(source_pos); + for (int i = 0; i < len; i++) { + dest[dest_pos + i] = tmp.getValue(); // copy + tmp = tmp.getNext(); + } + + return dest; + } + + /** {@inheritDoc} */ + public boolean forEach(TFloatProcedure procedure) { + for (TFloatLink l = head; got(l); l = l.getNext()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean forEachDescending(TFloatProcedure procedure) { + for (TFloatLink l = tail; got(l); l = l.getPrevious()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public void sort() { + sort(0, size); + } + + /** {@inheritDoc} */ + public void sort(int fromIndex, int toIndex) { + TFloatList tmp = subList(fromIndex, toIndex); + float[] vals = tmp.toArray(); + Arrays.sort(vals); + set(fromIndex, vals); + } + + /** {@inheritDoc} */ + public void fill(float val) { + fill(0, size, val); + } + + /** {@inheritDoc} */ + public void fill(int fromIndex, int toIndex, float val) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + + TFloatLink l = getLinkAt(fromIndex); + if (toIndex > size) { + for (int i = fromIndex; i < size; i++) { + l.setValue(val); + l = l.getNext(); + } + for (int i = size; i < toIndex; i++) { + add(val); + } + } else { + for (int i = fromIndex; i < toIndex; i++) { + l.setValue(val); + l = l.getNext(); + } + } + + } + + /** {@inheritDoc} */ + public int binarySearch(float value) { + return binarySearch(value, 0, size()); + } + + /** {@inheritDoc} */ + public int binarySearch(float value, int fromIndex, int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + if (toIndex > size) { + throw new IndexOutOfBoundsException("end index > size: " + toIndex + " > " + size); + } + + + if (toIndex < fromIndex) { + return -(fromIndex+1); + } + + TFloatLink middle; + int mid; + int from = fromIndex; + TFloatLink fromLink = getLinkAt(fromIndex); + int to = toIndex; + + while (from < to) { + mid = (from + to) >>> 1; + middle = getLink(fromLink, from, mid); + if (middle.getValue() == value) + return mid; + + if (middle.getValue() < value) { + from = mid + 1; + fromLink = middle.next; + } else { + to = mid - 1; + } + } + + return -(from + 1); + } + + /** {@inheritDoc} */ + public int indexOf(float value) { + return indexOf(0, value); + } + + /** {@inheritDoc} */ + public int indexOf(int offset, float value) { + int count = offset; + + TFloatLink l; + for (l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + return count; + + count++; + } + + if ( l != null && l.getValue() == value ) return count; + + return -1; + } + + /** {@inheritDoc} */ + public int lastIndexOf(float value) { + return lastIndexOf(0, value); + } + + /** {@inheritDoc} */ + public int lastIndexOf(int offset, float value) { + if (isEmpty()) + return -1; + + int last = -1; + int count = offset; + for (TFloatLink l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + last = count; + + count++; + } + + return last; + } + + /** {@inheritDoc} */ + public boolean contains(float value) { + if (isEmpty()) + return false; + + for (TFloatLink l = head; got(l); l = l.getNext()) { + if (l.getValue() == value) + return true; + } + return false; + + } + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatIterator() { + TFloatLink l = head; + TFloatLink current; + + public float next() { + if (no(l)) + throw new NoSuchElementException(); + + float ret = l.getValue(); + current = l; + l = l.getNext(); + + return ret; + } + + public boolean hasNext() { + return got(l); + } + + public void remove() { + if (current == null) + throw new IllegalStateException(); + + removeLink(current); + current = null; + } + }; + } + + /** {@inheritDoc} */ + public TFloatList grep(TFloatProcedure condition) { + TFloatList ret = new TFloatLinkedList(); + for (TFloatLink l = head; got(l); l = l.getNext()) { + if (condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public TFloatList inverseGrep(TFloatProcedure condition) { + TFloatList ret = new TFloatLinkedList(); + for (TFloatLink l = head; got(l); l = l.getNext()) { + if (!condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public float max() { + float ret = Float.NEGATIVE_INFINITY; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TFloatLink l = head; got(l); l = l.getNext()) { + if (ret < l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public float min() { + float ret = Float.POSITIVE_INFINITY; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TFloatLink l = head; got(l); l = l.getNext()) { + if (ret > l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public float sum() { + float sum = 0; + + for (TFloatLink l = head; got(l); l = l.getNext()) { + sum += l.getValue(); + } + + return sum; + } + + // + // + // + static class TFloatLink { + float value; + TFloatLink previous; + TFloatLink next; + + TFloatLink(float value) { + this.value = value; + } + + public float getValue() { + return value; + } + + public void setValue(float value) { + this.value = value; + } + + public TFloatLink getPrevious() { + return previous; + } + + public void setPrevious(TFloatLink previous) { + this.previous = previous; + } + + public TFloatLink getNext() { + return next; + } + + public void setNext(TFloatLink next) { + this.next = next; + } + } + + class RemoveProcedure implements TFloatProcedure { + boolean changed = false; + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(float value) { + if (remove(value)) + changed = true; + + return true; + } + + public boolean isChanged() { + return changed; + } + } + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // NO_ENTRY_VALUE + out.writeFloat(no_entry_value); + + // ENTRIES + out.writeInt(size); + for (TFloatIterator iterator = iterator(); iterator.hasNext();) { + float next = iterator.next(); + out.writeFloat(next); + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + + // ENTRIES + int len = in.readInt(); + for (int i = 0; i < len; i++) { + add(in.readFloat()); + } + } + + static boolean got(Object ref) { + return ref != null; + } + + static boolean no(Object ref) { + return ref == null; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TFloatList ) ) return false; + + TFloatList that = ( TFloatList )other; + if ( size() != that.size() ) return false; + + for( int i = 0; i < size(); i++ ) { + if ( get( i ) != that.get( i ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = size(); i-- > 0; ) { + h += HashFunctions.hash( get( i ) ); + } + return h; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + TFloatIterator it = iterator(); + while (it.hasNext()) { + float next = it.next(); + buf.append(next); + if (it.hasNext()) + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + + } +} // TFloatLinkedList diff --git a/src/gnu/trove/list/linked/TIntLinkedList.java b/src/gnu/trove/list/linked/TIntLinkedList.java new file mode 100644 index 0000000..58c43ba --- /dev/null +++ b/src/gnu/trove/list/linked/TIntLinkedList.java @@ -0,0 +1,1059 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// Copyright (c) 2011, Johan Parent All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.linked; + +import gnu.trove.function.TIntFunction; +import gnu.trove.list.TIntList; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.TIntCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, double linked list of int primitives. + */ +public class TIntLinkedList implements TIntList, Externalizable { + private int no_entry_value; + private int size; + + private TIntLink head = null; + private TIntLink tail = head; + + public TIntLinkedList() { + this( Constants.DEFAULT_INT_NO_ENTRY_VALUE ); + } + + public TIntLinkedList(int no_entry_value) { + this.no_entry_value = no_entry_value; + } + + public TIntLinkedList(TIntList list) { + no_entry_value = list.getNoEntryValue(); + // + for (TIntIterator iterator = list.iterator(); iterator.hasNext();) { + int next = iterator.next(); + add(next); + } + } + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + public boolean add(int val) { + TIntLink l = new TIntLink(val); + if (no(head)) { + head = l; + tail = l; + } else { + l.setPrevious(tail); + tail.setNext(l); + // + tail = l; + } + + size++; + return true; + } + + /** {@inheritDoc} */ + public void add(int[] vals) { + for (int val : vals) { + add(val); + } + } + + /** {@inheritDoc} */ + public void add(int[] vals, int offset, int length) { + for (int i = 0; i < length; i++) { + int val = vals[offset + i]; + add(val); + } + } + + /** {@inheritDoc} */ + public void insert(int offset, int value) { + TIntLinkedList tmp = new TIntLinkedList(); + tmp.add(value); + insert(offset, tmp); + } + + /** {@inheritDoc} */ + public void insert(int offset, int[] values) { + insert(offset, link(values, 0, values.length)); + } + + /** {@inheritDoc} */ + public void insert(int offset, int[] values, int valOffset, int len) { + insert(offset, link(values, valOffset, len)); + } + + void insert(int offset, TIntLinkedList tmp) { + TIntLink l = getLinkAt(offset); + + size = size + tmp.size; + // + if (l == head) { + // Add in front + tmp.tail.setNext(head); + head.setPrevious(tmp.tail); + head = tmp.head; + + return; + } + + if (no(l)) { + if (size == 0) { + // New empty list + head = tmp.head; + tail = tmp.tail; + } else { + // append + tail.setNext(tmp.head); + tmp.head.setPrevious(tail); + tail = tmp.tail; + } + } else { + TIntLink prev = l.getPrevious(); + l.getPrevious().setNext(tmp.head); + + // Link by behind tmp + tmp.tail.setNext(l); + l.setPrevious(tmp.tail); + + tmp.head.setPrevious(prev); + } + } + + static TIntLinkedList link(int[] values, int valOffset, int len) { + TIntLinkedList ret = new TIntLinkedList(); + + for (int i = 0; i < len; i++) { + ret.add(values[valOffset + i]); + } + + return ret; + } + + /** {@inheritDoc} */ + public int get(int offset) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TIntLink l = getLinkAt(offset); + // + if (no(l)) + return no_entry_value; + + return l.getValue(); + } + + /** + * Returns the link at the given offset. + *

+ * A simple bisection criteria is used to keep the worst case complexity equal to + * O(n/2) where n = size(). Simply start from head of list or tail depending on offset + * and list size. + * + * @param offset of the link + * @return link or null if non-existent + */ + public TIntLink getLinkAt(int offset) { + if (offset >= size()) + return null; + + if (offset <= (size() >>> 1)) + return getLink(head, 0, offset, true); + else + return getLink(tail, size() - 1, offset, false); + } + + /** + * Returns the link at absolute offset starting from given the initial link 'l' at index 'idx' + * + * @param l + * @param idx + * @param offset + * @return + */ + private static TIntLink getLink(TIntLink l, int idx, int offset) { + return getLink(l, idx, offset, true); + } + + /** + * Returns link at given absolute offset starting from link 'l' at index 'idx' + * @param l + * @param idx + * @param offset + * @param next + * @return + */ + private static TIntLink getLink(TIntLink l, int idx, int offset, boolean next) { + int i = idx; + // + while (got(l)) { + if (i == offset) { + return l; + } + + i = i + (next ? 1 : -1); + l = next ? l.getNext() : l.getPrevious(); + } + + return null; + } + + + /** {@inheritDoc} */ + public int set(int offset, int val) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TIntLink l = getLinkAt(offset); + // + if (no(l)) + throw new IndexOutOfBoundsException("at offset " + offset); + + int prev = l.getValue(); + l.setValue(val); + return prev; + } + + /** {@inheritDoc} */ + public void set(int offset, int[] values) { + set(offset, values, 0, values.length); + } + + /** {@inheritDoc} */ + public void set(int offset, int[] values, int valOffset, int length) { + for (int i = 0; i < length; i++) { + int value = values[valOffset + i]; + set(offset + i, value); + } + } + + /** {@inheritDoc} */ + public int replace(int offset, int val) { + return set(offset, val); + } + + /** {@inheritDoc} */ + public void clear() { + size = 0; + // + head = null; + tail = null; + } + + /** {@inheritDoc} */ + public boolean remove(int value) { + boolean changed = false; + for (TIntLink l = head; got(l); l = l.getNext()) { + // + if (l.getValue() == value) { + changed = true; + // + removeLink(l); + } + } + + return changed; + } + + /** + * unlinks the give TIntLink from the list + * + * @param l + */ + private void removeLink(TIntLink l) { + if (no(l)) + return; + + size--; + + TIntLink prev = l.getPrevious(); + TIntLink next = l.getNext(); + + if (got(prev)) { + prev.setNext(next); + } else { + // No previous we must be head + head = next; + } + + if (got(next)) { + next.setPrevious(prev); + } else { + // No next so me must be tail + tail = prev; + } + // Unlink + l.setNext(null); + l.setPrevious(null); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + if (isEmpty()) + return false; + + for (Object o : collection) { + if (o instanceof Integer) { + Integer i = (Integer) o; + if (!(contains(i))) + return false; + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(TIntCollection collection) { + if (isEmpty()) + return false; + + for (TIntIterator it = collection.iterator(); it.hasNext();) { + int i = it.next(); + if (!(contains(i))) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(int[] array) { + if (isEmpty()) + return false; + + for (int i : array) { + if (!contains(i)) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + boolean ret = false; + for (Integer v : collection) { + if (add(v.intValue())) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(TIntCollection collection) { + boolean ret = false; + for (TIntIterator it = collection.iterator(); it.hasNext();) { + int i = it.next(); + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(int[] array) { + boolean ret = false; + for (int i : array) { + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + boolean modified = false; + TIntIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(Integer.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(TIntCollection collection) { + boolean modified = false; + TIntIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(int[] array) { + Arrays.sort(array); + + boolean modified = false; + TIntIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) < 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + boolean modified = false; + TIntIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(Integer.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(TIntCollection collection) { + boolean modified = false; + TIntIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(int[] array) { + Arrays.sort(array); + + boolean modified = false; + TIntIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) >= 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public int removeAt(int offset) { + TIntLink l = getLinkAt(offset); + if (no(l)) + throw new ArrayIndexOutOfBoundsException("no elemenet at " + offset); + + int prev = l.getValue(); + removeLink(l); + return prev; + } + + /** {@inheritDoc} */ + public void remove(int offset, int length) { + for (int i = 0; i < length; i++) { + removeAt(offset); // since the list shrinks we don't need to use offset+i to get the next entry ;) + } + } + + /** {@inheritDoc} */ + public void transformValues(TIntFunction function) { + for (TIntLink l = head; got(l);) { + // + l.setValue(function.execute(l.getValue())); + // + l = l.getNext(); + } + } + + /** {@inheritDoc} */ + public void reverse() { + TIntLink h = head; + TIntLink t = tail; + TIntLink prev, next, tmp; + + // + TIntLink l = head; + while (got(l)) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // + head = t; + tail = h; + } + + /** {@inheritDoc} */ + public void reverse(int from, int to) { + if (from > to) + throw new IllegalArgumentException("from > to : " + from + ">" + to); + + TIntLink start = getLinkAt(from); + TIntLink stop = getLinkAt(to); + TIntLink prev, next; + TIntLink tmp = null; + + TIntLink tmpHead = start.getPrevious(); + + // + TIntLink l = start; + while (l != stop) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // At this point l == stop and tmp is the but last element { + if (got(tmp)) { + tmpHead.setNext(tmp); + stop.setPrevious(tmpHead); + } + start.setNext(stop); + stop.setPrevious(start); + } + + /** {@inheritDoc} */ + public void shuffle(Random rand) { + for (int i = 0; i < size; i++) { + TIntLink l = getLinkAt(rand.nextInt(size())); + removeLink(l); + add(l.getValue()); + } + } + + /** {@inheritDoc} */ + public TIntList subList(int begin, int end) { + if (end < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than end index " + end); + } + if (size < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than last index " + size); + } + if (begin < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + if (end > size) { + throw new IndexOutOfBoundsException("end index < " + size); + } + + TIntLinkedList ret = new TIntLinkedList(); + TIntLink tmp = getLinkAt(begin); + for (int i = begin; i < end; i++) { + ret.add(tmp.getValue()); // copy + tmp = tmp.getNext(); + } + + return ret; + } + + /** {@inheritDoc} */ + public int[] toArray() { + return toArray(new int[size], 0, size); + } + + /** {@inheritDoc} */ + public int[] toArray(int offset, int len) { + return toArray(new int[len], offset, 0, len); + } + + /** {@inheritDoc} */ + public int[] toArray(int[] dest) { + return toArray(dest, 0, size); + } + + /** {@inheritDoc} */ + public int[] toArray(int[] dest, int offset, int len) { + return toArray(dest, offset, 0, len); + } + + /** {@inheritDoc} */ + public int[] toArray(int[] dest, int source_pos, int dest_pos, int len) { + if (len == 0) { + return dest; // nothing to copy + } + if (source_pos < 0 || source_pos >= size()) { + throw new ArrayIndexOutOfBoundsException(source_pos); + } + + TIntLink tmp = getLinkAt(source_pos); + for (int i = 0; i < len; i++) { + dest[dest_pos + i] = tmp.getValue(); // copy + tmp = tmp.getNext(); + } + + return dest; + } + + /** {@inheritDoc} */ + public boolean forEach(TIntProcedure procedure) { + for (TIntLink l = head; got(l); l = l.getNext()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean forEachDescending(TIntProcedure procedure) { + for (TIntLink l = tail; got(l); l = l.getPrevious()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public void sort() { + sort(0, size); + } + + /** {@inheritDoc} */ + public void sort(int fromIndex, int toIndex) { + TIntList tmp = subList(fromIndex, toIndex); + int[] vals = tmp.toArray(); + Arrays.sort(vals); + set(fromIndex, vals); + } + + /** {@inheritDoc} */ + public void fill(int val) { + fill(0, size, val); + } + + /** {@inheritDoc} */ + public void fill(int fromIndex, int toIndex, int val) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + + TIntLink l = getLinkAt(fromIndex); + if (toIndex > size) { + for (int i = fromIndex; i < size; i++) { + l.setValue(val); + l = l.getNext(); + } + for (int i = size; i < toIndex; i++) { + add(val); + } + } else { + for (int i = fromIndex; i < toIndex; i++) { + l.setValue(val); + l = l.getNext(); + } + } + + } + + /** {@inheritDoc} */ + public int binarySearch(int value) { + return binarySearch(value, 0, size()); + } + + /** {@inheritDoc} */ + public int binarySearch(int value, int fromIndex, int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + if (toIndex > size) { + throw new IndexOutOfBoundsException("end index > size: " + toIndex + " > " + size); + } + + + if (toIndex < fromIndex) { + return -(fromIndex+1); + } + + TIntLink middle; + int mid; + int from = fromIndex; + TIntLink fromLink = getLinkAt(fromIndex); + int to = toIndex; + + while (from < to) { + mid = (from + to) >>> 1; + middle = getLink(fromLink, from, mid); + if (middle.getValue() == value) + return mid; + + if (middle.getValue() < value) { + from = mid + 1; + fromLink = middle.next; + } else { + to = mid - 1; + } + } + + return -(from + 1); + } + + /** {@inheritDoc} */ + public int indexOf(int value) { + return indexOf(0, value); + } + + /** {@inheritDoc} */ + public int indexOf(int offset, int value) { + int count = offset; + + TIntLink l; + for (l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + return count; + + count++; + } + + if ( l != null && l.getValue() == value ) return count; + + return -1; + } + + /** {@inheritDoc} */ + public int lastIndexOf(int value) { + return lastIndexOf(0, value); + } + + /** {@inheritDoc} */ + public int lastIndexOf(int offset, int value) { + if (isEmpty()) + return -1; + + int last = -1; + int count = offset; + for (TIntLink l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + last = count; + + count++; + } + + return last; + } + + /** {@inheritDoc} */ + public boolean contains(int value) { + if (isEmpty()) + return false; + + for (TIntLink l = head; got(l); l = l.getNext()) { + if (l.getValue() == value) + return true; + } + return false; + + } + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntIterator() { + TIntLink l = head; + TIntLink current; + + public int next() { + if (no(l)) + throw new NoSuchElementException(); + + int ret = l.getValue(); + current = l; + l = l.getNext(); + + return ret; + } + + public boolean hasNext() { + return got(l); + } + + public void remove() { + if (current == null) + throw new IllegalStateException(); + + removeLink(current); + current = null; + } + }; + } + + /** {@inheritDoc} */ + public TIntList grep(TIntProcedure condition) { + TIntList ret = new TIntLinkedList(); + for (TIntLink l = head; got(l); l = l.getNext()) { + if (condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public TIntList inverseGrep(TIntProcedure condition) { + TIntList ret = new TIntLinkedList(); + for (TIntLink l = head; got(l); l = l.getNext()) { + if (!condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public int max() { + int ret = Integer.MIN_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TIntLink l = head; got(l); l = l.getNext()) { + if (ret < l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public int min() { + int ret = Integer.MAX_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TIntLink l = head; got(l); l = l.getNext()) { + if (ret > l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public int sum() { + int sum = 0; + + for (TIntLink l = head; got(l); l = l.getNext()) { + sum += l.getValue(); + } + + return sum; + } + + // + // + // + static class TIntLink { + int value; + TIntLink previous; + TIntLink next; + + TIntLink(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public TIntLink getPrevious() { + return previous; + } + + public void setPrevious(TIntLink previous) { + this.previous = previous; + } + + public TIntLink getNext() { + return next; + } + + public void setNext(TIntLink next) { + this.next = next; + } + } + + class RemoveProcedure implements TIntProcedure { + boolean changed = false; + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(int value) { + if (remove(value)) + changed = true; + + return true; + } + + public boolean isChanged() { + return changed; + } + } + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // NO_ENTRY_VALUE + out.writeInt(no_entry_value); + + // ENTRIES + out.writeInt(size); + for (TIntIterator iterator = iterator(); iterator.hasNext();) { + int next = iterator.next(); + out.writeInt(next); + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + + // ENTRIES + int len = in.readInt(); + for (int i = 0; i < len; i++) { + add(in.readInt()); + } + } + + static boolean got(Object ref) { + return ref != null; + } + + static boolean no(Object ref) { + return ref == null; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TIntList ) ) return false; + + TIntList that = ( TIntList )other; + if ( size() != that.size() ) return false; + + for( int i = 0; i < size(); i++ ) { + if ( get( i ) != that.get( i ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = size(); i-- > 0; ) { + h += HashFunctions.hash( get( i ) ); + } + return h; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + TIntIterator it = iterator(); + while (it.hasNext()) { + int next = it.next(); + buf.append(next); + if (it.hasNext()) + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + + } +} // TIntLinkedList diff --git a/src/gnu/trove/list/linked/TLinkedList.java b/src/gnu/trove/list/linked/TLinkedList.java new file mode 100644 index 0000000..236a6e2 --- /dev/null +++ b/src/gnu/trove/list/linked/TLinkedList.java @@ -0,0 +1,850 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.list.linked; + +import gnu.trove.list.TLinkable; +import gnu.trove.procedure.TObjectProcedure; + +import java.io.*; +import java.util.AbstractSequentialList; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.lang.reflect.Array; + + + +/** + *

A LinkedList implementation which holds instances of type + * TLinkable. + *

+ * Using this implementation allows you to get java.util.LinkedList + * behavior (a doubly linked list, with Iterators that support insert + * and delete operations) without incurring the overhead of creating + * Node wrapper objects for every element in your list. + *

+ * The requirement to achieve this time/space gain is that the + * Objects stored in the List implement the TLinkable + * interface. + *

+ * The limitations are:

    + *
  • the same object cannot be put into more than one list at the same time. + *
  • the same object cannot be put into the same list more than once at the same time. + *
  • objects must only be removed from list they are in. That is, + * if you have an object A and lists l1 and l2, you must ensure that + * you invoke List.remove(A) on the correct list. + *
  • It is also forbidden to invoke List.remove() with an unaffiliated + * TLinkable (one that belongs to no list): this will destroy the list + * you invoke it on. + *
+ * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: TLinkedList.java,v 1.1.2.3 2010/09/27 17:23:07 robeden Exp $ + * @see gnu.trove.list.TLinkable + */ + + +public class TLinkedList> extends AbstractSequentialList + implements Externalizable { + + static final long serialVersionUID = 1L; + + + /** the head of the list */ + protected T _head; + /** the tail of the list */ + protected T _tail; + /** the number of elements in the list */ + protected int _size = 0; + + + /** Creates a new TLinkedList instance. */ + public TLinkedList() { + super(); + } + + + /** + * Returns an iterator positioned at index. Assuming + * that the list has a value at that index, calling next() will + * retrieve and advance the iterator. Assuming that there is a + * value before index in the list, calling previous() + * will retrieve it (the value at index - 1) and move the iterator + * to that position. So, iterating from front to back starts at + * 0; iterating from back to front starts at size(). + * + * @param index an int value + * @return a ListIterator value + */ + public ListIterator listIterator( int index ) { + return new IteratorImpl( index ); + } + + + /** + * Returns the number of elements in the list. + * + * @return an int value + */ + public int size() { + return _size; + } + + + /** + * Inserts linkable at index index in the list. + * All values > index are shifted over one position to accommodate + * the new addition. + * + * @param index an int value + * @param linkable an object of type TLinkable + */ + public void add( int index, T linkable ) { + if ( index < 0 || index > size() ) { + throw new IndexOutOfBoundsException( "index:" + index ); + } + insert( index, linkable ); + } + + + /** + * Appends linkable to the end of the list. + * + * @param linkable an object of type TLinkable + * @return always true + */ + public boolean add( T linkable ) { + insert( _size, linkable ); + return true; + } + + + /** + * Inserts linkable at the head of the list. + * + * @param linkable an object of type TLinkable + */ + public void addFirst( T linkable ) { + insert( 0, linkable ); + } + + + /** + * Adds linkable to the end of the list. + * + * @param linkable an object of type TLinkable + */ + public void addLast( T linkable ) { + insert( size(), linkable ); + } + + + /** Empties the list. */ + public void clear() { + if ( null != _head ) { + for ( TLinkable link = _head.getNext(); + link != null; + link = link.getNext() ) { + TLinkable prev = link.getPrevious(); + prev.setNext( null ); + link.setPrevious( null ); + } + _head = _tail = null; + } + _size = 0; + } + + + /** + * Copies the list's contents into a native array. This will be a + * shallow copy: the Tlinkable instances in the Object[] array + * have links to one another: changing those will put this list + * into an unpredictable state. Holding a reference to one + * element in the list will prevent the others from being garbage + * collected unless you clear the next/previous links. Caveat + * programmer! + * + * @return an Object[] value + */ + @SuppressWarnings("rawtypes") + public Object[] toArray() { + Object[] o = new Object[_size]; + int i = 0; + for ( TLinkable link = _head; link != null; link = link.getNext() ) { + o[i++] = link; + } + return o; + } + + + /** + * Copies the list to a native array, destroying the next/previous + * links as the copy is made. This list will be emptied after the + * copy (as if clear() had been invoked). The Object[] array + * returned will contain TLinkables that do not hold + * references to one another and so are less likely to be the + * cause of memory leaks. + * + * @return an Object[] value + */ + public Object[] toUnlinkedArray() { + Object[] o = new Object[_size]; + int i = 0; + for ( TLinkable link = _head, tmp; link != null; i++ ) { + o[i] = link; + tmp = link; + link = link.getNext(); + tmp.setNext( null ); // clear the links + tmp.setPrevious( null ); + } + _size = 0; // clear the list + _head = _tail = null; + return o; + } + + + /** + * Returns a typed array of the objects in the set. + * + * @param a an Object[] value + * @return an Object[] value + */ + @SuppressWarnings({"unchecked"}) + public T[] toUnlinkedArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) Array.newInstance( a.getClass().getComponentType(), size ); + } + + int i = 0; + for ( T link = _head, tmp; link != null; i++ ) { + a[i] = link; + tmp = link; + link = link.getNext(); + tmp.setNext( null ); // clear the links + tmp.setPrevious( null ); + } + _size = 0; // clear the list + _head = _tail = null; + return a; + } + + + /** + * A linear search for o in the list. + * + * @param o an Object value + * @return a boolean value + */ + public boolean contains( Object o ) { + for ( TLinkable link = _head; link != null; link = link.getNext() ) { + if ( o.equals( link ) ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + @Override + @SuppressWarnings({}) + public T get( int index ) { + // Blow out for bogus values + if ( index < 0 || index >= _size ) { + throw new IndexOutOfBoundsException( "Index: " + index + ", Size: " + _size ); + } + + // Determine if it's better to get there from the front or the back + if ( index > ( _size >> 1 ) ) { + int position = _size - 1; + T node = _tail; + + while ( position > index ) { + node = node.getPrevious(); + position--; + } + + return node; + } else { + int position = 0; + T node = _head; + + while ( position < index ) { + node = node.getNext(); + position++; + } + + return node; + } + } + + + /** + * Returns the head of the list + * + * @return an Object value + */ + public T getFirst() { + return _head; + } + + + /** + * Returns the tail of the list. + * + * @return an Object value + */ + public T getLast() { + return _tail; + } + + + /** + * Return the node following the given node. This method exists for two reasons: + *
    + *
  1. It's really not recommended that the methods implemented by TLinkable be + * called directly since they're used internally by this class.
  2. + *
  3. This solves problems arising from generics when working with the linked + * objects directly.
  4. + *
+ *

+ * NOTE: this should only be used with nodes contained in the list. The results are + * undefined with anything else. + * + * @param current The current node + * @return the node after the current node + */ + @SuppressWarnings({}) + public T getNext( T current ) { + return current.getNext(); + } + + + /** + * Return the node preceding the given node. This method exists for two reasons: + *

    + *
  1. It's really not recommended that the methods implemented by TLinkable be + * called directly since they're used internally by this class.
  2. + *
  3. This solves problems arising from generics when working with the linked + * objects directly.
  4. + *
+ *

+ * NOTE: this should only be used with nodes contained in the list. The results are + * undefined with anything else. + * + * @param current The current node + * @return the node after the current node + */ + @SuppressWarnings({}) + public T getPrevious( T current ) { + return current.getPrevious(); + } + + + /** + * Remove and return the first element in the list. + * + * @return an Object value + */ + @SuppressWarnings({}) + public T removeFirst() { + T o = _head; + + if ( o == null ) { + return null; + } + + T n = o.getNext(); + o.setNext( null ); + + if ( null != n ) { + n.setPrevious( null ); + } + + _head = n; + if ( --_size == 0 ) { + _tail = null; + } + return o; + } + + + /** + * Remove and return the last element in the list. + * + * @return an Object value + */ + @SuppressWarnings({}) + public T removeLast() { + T o = _tail; + + if ( o == null ) { + return null; + } + + T prev = o.getPrevious(); + o.setPrevious( null ); + + if ( null != prev ) { + prev.setNext( null ); + } + _tail = prev; + if ( --_size == 0 ) { + _head = null; + } + return o; + } + + + /** + * Implementation of index-based list insertions. + * + * @param index an int value + * @param linkable an object of type TLinkable + */ + @SuppressWarnings({}) + protected void insert( int index, T linkable ) { + + if ( _size == 0 ) { + _head = _tail = linkable; // first insertion + } else if ( index == 0 ) { + linkable.setNext( _head ); // insert at front + _head.setPrevious( linkable ); + _head = linkable; + } else if ( index == _size ) { // insert at back + _tail.setNext( linkable ); + linkable.setPrevious( _tail ); + _tail = linkable; + } else { + T node = get( index ); + + T before = node.getPrevious(); + if ( before != null ) { + before.setNext( linkable ); + } + + linkable.setPrevious( before ); + linkable.setNext( node ); + node.setPrevious( linkable ); + } + _size++; + } + + + /** + * Removes the specified element from the list. Note that + * it is the caller's responsibility to ensure that the + * element does, in fact, belong to this list and not another + * instance of TLinkedList. + * + * @param o a TLinkable element already inserted in this list. + * @return true if the element was a TLinkable and removed + */ + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + if ( o instanceof TLinkable ) { + T p, n; + TLinkable link = (TLinkable) o; + + p = link.getPrevious(); + n = link.getNext(); + + if ( n == null && p == null ) { // emptying the list + // It's possible this object is not something that's in the list. So, + // make sure it's the head if it doesn't point to anything. This solves + // problems caused by removing something multiple times. + if ( o != _head ) { + return false; + } + + _head = _tail = null; + } else if ( n == null ) { // this is the tail + // make previous the new tail + link.setPrevious( null ); + p.setNext( null ); + _tail = p; + } else if ( p == null ) { // this is the head + // make next the new head + link.setNext( null ); + n.setPrevious( null ); + _head = n; + } else { // somewhere in the middle + p.setNext( n ); + n.setPrevious( p ); + link.setNext( null ); + link.setPrevious( null ); + } + + _size--; // reduce size of list + return true; + } else { + return false; + } + } + + + /** + * Inserts newElement into the list immediately before current. + * All elements to the right of and including current are shifted + * over. + * + * @param current a TLinkable value currently in the list. + * @param newElement a TLinkable value to be added to + * the list. + */ + public void addBefore( T current, T newElement ) { + if ( current == _head ) { + addFirst( newElement ); + } else if ( current == null ) { + addLast( newElement ); + } else { + T p = current.getPrevious(); + newElement.setNext( current ); + p.setNext( newElement ); + newElement.setPrevious( p ); + current.setPrevious( newElement ); + _size++; + } + } + + + /** + * Inserts newElement into the list immediately after current. + * All elements to the left of and including current are shifted + * over. + * + * @param current a TLinkable value currently in the list. + * @param newElement a TLinkable value to be added to + * the list. + */ + public void addAfter( T current, T newElement ) { + if ( current == _tail ) { + addLast( newElement ); + } else if ( current == null ) { + addFirst( newElement ); + } else { + T n = current.getNext(); + newElement.setPrevious( current ); + newElement.setNext( n ); + current.setNext( newElement ); + n.setPrevious( newElement ); + _size++; + } + } + + + /** + * Executes procedure for each entry in the list. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + @SuppressWarnings({}) + public boolean forEachValue( TObjectProcedure procedure ) { + T node = _head; + while ( node != null ) { + boolean keep_going = procedure.execute( node ); + if ( !keep_going ) { + return false; + } + + node = node.getNext(); + } + + return true; + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // HEAD + out.writeObject( _head ); + + // TAIL + out.writeObject( _tail ); + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NUMBER OF ENTRIED + _size = in.readInt(); + + // HEAD + _head = (T) in.readObject(); + + // TAIL + _tail = (T) in.readObject(); + } + + + /** A ListIterator that supports additions and deletions. */ + protected final class IteratorImpl implements ListIterator { + + private int _nextIndex = 0; + private T _next; + private T _lastReturned; + + + /** + * Creates a new Iterator instance positioned at + * index. + * + * @param position an int value + */ + @SuppressWarnings({}) + IteratorImpl( int position ) { + if ( position < 0 || position > _size ) { + throw new IndexOutOfBoundsException(); + } + + _nextIndex = position; + if ( position == 0 ) { + _next = _head; + } else if ( position == _size ) { + _next = null; + } else if ( position < ( _size >> 1 ) ) { + int pos = 0; + for ( _next = _head; pos < position; pos++ ) { + _next = _next.getNext(); + } + } else { + int pos = _size - 1; + for ( _next = _tail; pos > position; pos-- ) { + _next = _next.getPrevious(); + } + } + } + + + /** + * Insert linkable at the current position of the iterator. + * Calling next() after add() will return the added object. + * + * @param linkable an object of type TLinkable + */ + public final void add( T linkable ) { + _lastReturned = null; + _nextIndex++; + + if ( _size == 0 ) { + TLinkedList.this.add( linkable ); + } else { + TLinkedList.this.addBefore( _next, linkable ); + } + } + + + /** + * True if a call to next() will return an object. + * + * @return a boolean value + */ + public final boolean hasNext() { + return _nextIndex != _size; + } + + + /** + * True if a call to previous() will return a value. + * + * @return a boolean value + */ + public final boolean hasPrevious() { + return _nextIndex != 0; + } + + + /** + * Returns the value at the Iterator's index and advances the + * iterator. + * + * @return an Object value + * @throws NoSuchElementException if there is no next element + */ + @SuppressWarnings({}) + public final T next() { + if ( _nextIndex == _size ) { + throw new NoSuchElementException(); + } + + _lastReturned = _next; + _next = _next.getNext(); + _nextIndex++; + return _lastReturned; + } + + + /** + * returns the index of the next node in the list (the + * one that would be returned by a call to next()). + * + * @return an int value + */ + public final int nextIndex() { + return _nextIndex; + } + + + /** + * Returns the value before the Iterator's index and moves the + * iterator back one index. + * + * @return an Object value + * @throws NoSuchElementException if there is no previous element. + */ + @SuppressWarnings({}) + public final T previous() { + if ( _nextIndex == 0 ) { + throw new NoSuchElementException(); + } + + if ( _nextIndex == _size ) { + _lastReturned = _next = _tail; + } else { + _lastReturned = _next = _next.getPrevious(); + } + + _nextIndex--; + return _lastReturned; + } + + + /** + * Returns the previous element's index. + * + * @return an int value + */ + public final int previousIndex() { + return _nextIndex - 1; + } + + + /** + * Removes the current element in the list and shrinks its + * size accordingly. + * + * @throws IllegalStateException neither next nor previous + * have been invoked, or remove or add have been invoked after + * the last invocation of next or previous. + */ + @SuppressWarnings({}) + public final void remove() { + if ( _lastReturned == null ) { + throw new IllegalStateException( "must invoke next or previous before invoking remove" ); + } + + if ( _lastReturned != _next ) { + _nextIndex--; + } + _next = _lastReturned.getNext(); + TLinkedList.this.remove( _lastReturned ); + _lastReturned = null; + } + + + /** + * Replaces the current element in the list with + * linkable + * + * @param linkable an object of type TLinkable + */ + public final void set( T linkable ) { + if ( _lastReturned == null ) { + throw new IllegalStateException(); + } + + swap( _lastReturned, linkable ); + _lastReturned = linkable; + } + + + /** + * Replace from with to in the list. + * + * @param from a TLinkable value + * @param to a TLinkable value + */ + private void swap( T from, T to ) { + T from_p = from.getPrevious(); + T from_n = from.getNext(); + + T to_p = to.getPrevious(); + T to_n = to.getNext(); + + // NOTE: 'to' cannot be null at this point + if ( from_n == to ) { + if ( from_p != null ) from_p.setNext( to ); + to.setPrevious( from_p ); + to.setNext( from ); + from.setPrevious( to ); + from.setNext( to_n ); + if ( to_n != null ) to_n.setPrevious( from ); + } + // NOTE: 'from' cannot be null at this point + else if ( to_n == from ) { + if ( to_p != null ) to_p.setNext( to ); + to.setPrevious( from ); + to.setNext( from_n ); + from.setPrevious( to_p ); + from.setNext( to ); + if ( from_n != null ) from_n.setPrevious( to ); + } + else { + from.setNext( to_n ); + from.setPrevious( to_p ); + if ( to_p != null ) to_p.setNext( from ); + if ( to_n != null ) to_n.setPrevious( from ); + + to.setNext( from_n ); + to.setPrevious( from_p ); + if ( from_p != null ) from_p.setNext( to ); + if ( from_n != null ) from_n.setPrevious( to ); + } + + if ( _head == from ) _head = to; + else if ( _head == to ) _head = from; + + if ( _tail == from ) _tail = to; + else if ( _tail == to ) _tail = from; + + if ( _lastReturned == from ) _lastReturned = to; + else if ( _lastReturned == to ) _lastReturned = from; + + if ( _next == from ) _next = to; + else if ( _next == to ) _next = from; + } + } +} // TLinkedList diff --git a/src/gnu/trove/list/linked/TLongLinkedList.java b/src/gnu/trove/list/linked/TLongLinkedList.java new file mode 100644 index 0000000..abbda91 --- /dev/null +++ b/src/gnu/trove/list/linked/TLongLinkedList.java @@ -0,0 +1,1059 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// Copyright (c) 2011, Johan Parent All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.linked; + +import gnu.trove.function.TLongFunction; +import gnu.trove.list.TLongList; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.TLongCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, double linked list of long primitives. + */ +public class TLongLinkedList implements TLongList, Externalizable { + private long no_entry_value; + private int size; + + private TLongLink head = null; + private TLongLink tail = head; + + public TLongLinkedList() { + this( Constants.DEFAULT_LONG_NO_ENTRY_VALUE ); + } + + public TLongLinkedList(long no_entry_value) { + this.no_entry_value = no_entry_value; + } + + public TLongLinkedList(TLongList list) { + no_entry_value = list.getNoEntryValue(); + // + for (TLongIterator iterator = list.iterator(); iterator.hasNext();) { + long next = iterator.next(); + add(next); + } + } + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + public boolean add(long val) { + TLongLink l = new TLongLink(val); + if (no(head)) { + head = l; + tail = l; + } else { + l.setPrevious(tail); + tail.setNext(l); + // + tail = l; + } + + size++; + return true; + } + + /** {@inheritDoc} */ + public void add(long[] vals) { + for (long val : vals) { + add(val); + } + } + + /** {@inheritDoc} */ + public void add(long[] vals, int offset, int length) { + for (int i = 0; i < length; i++) { + long val = vals[offset + i]; + add(val); + } + } + + /** {@inheritDoc} */ + public void insert(int offset, long value) { + TLongLinkedList tmp = new TLongLinkedList(); + tmp.add(value); + insert(offset, tmp); + } + + /** {@inheritDoc} */ + public void insert(int offset, long[] values) { + insert(offset, link(values, 0, values.length)); + } + + /** {@inheritDoc} */ + public void insert(int offset, long[] values, int valOffset, int len) { + insert(offset, link(values, valOffset, len)); + } + + void insert(int offset, TLongLinkedList tmp) { + TLongLink l = getLinkAt(offset); + + size = size + tmp.size; + // + if (l == head) { + // Add in front + tmp.tail.setNext(head); + head.setPrevious(tmp.tail); + head = tmp.head; + + return; + } + + if (no(l)) { + if (size == 0) { + // New empty list + head = tmp.head; + tail = tmp.tail; + } else { + // append + tail.setNext(tmp.head); + tmp.head.setPrevious(tail); + tail = tmp.tail; + } + } else { + TLongLink prev = l.getPrevious(); + l.getPrevious().setNext(tmp.head); + + // Link by behind tmp + tmp.tail.setNext(l); + l.setPrevious(tmp.tail); + + tmp.head.setPrevious(prev); + } + } + + static TLongLinkedList link(long[] values, int valOffset, int len) { + TLongLinkedList ret = new TLongLinkedList(); + + for (int i = 0; i < len; i++) { + ret.add(values[valOffset + i]); + } + + return ret; + } + + /** {@inheritDoc} */ + public long get(int offset) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TLongLink l = getLinkAt(offset); + // + if (no(l)) + return no_entry_value; + + return l.getValue(); + } + + /** + * Returns the link at the given offset. + *

+ * A simple bisection criteria is used to keep the worst case complexity equal to + * O(n/2) where n = size(). Simply start from head of list or tail depending on offset + * and list size. + * + * @param offset of the link + * @return link or null if non-existent + */ + public TLongLink getLinkAt(int offset) { + if (offset >= size()) + return null; + + if (offset <= (size() >>> 1)) + return getLink(head, 0, offset, true); + else + return getLink(tail, size() - 1, offset, false); + } + + /** + * Returns the link at absolute offset starting from given the initial link 'l' at index 'idx' + * + * @param l + * @param idx + * @param offset + * @return + */ + private static TLongLink getLink(TLongLink l, int idx, int offset) { + return getLink(l, idx, offset, true); + } + + /** + * Returns link at given absolute offset starting from link 'l' at index 'idx' + * @param l + * @param idx + * @param offset + * @param next + * @return + */ + private static TLongLink getLink(TLongLink l, int idx, int offset, boolean next) { + int i = idx; + // + while (got(l)) { + if (i == offset) { + return l; + } + + i = i + (next ? 1 : -1); + l = next ? l.getNext() : l.getPrevious(); + } + + return null; + } + + + /** {@inheritDoc} */ + public long set(int offset, long val) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TLongLink l = getLinkAt(offset); + // + if (no(l)) + throw new IndexOutOfBoundsException("at offset " + offset); + + long prev = l.getValue(); + l.setValue(val); + return prev; + } + + /** {@inheritDoc} */ + public void set(int offset, long[] values) { + set(offset, values, 0, values.length); + } + + /** {@inheritDoc} */ + public void set(int offset, long[] values, int valOffset, int length) { + for (int i = 0; i < length; i++) { + long value = values[valOffset + i]; + set(offset + i, value); + } + } + + /** {@inheritDoc} */ + public long replace(int offset, long val) { + return set(offset, val); + } + + /** {@inheritDoc} */ + public void clear() { + size = 0; + // + head = null; + tail = null; + } + + /** {@inheritDoc} */ + public boolean remove(long value) { + boolean changed = false; + for (TLongLink l = head; got(l); l = l.getNext()) { + // + if (l.getValue() == value) { + changed = true; + // + removeLink(l); + } + } + + return changed; + } + + /** + * unlinks the give TLongLink from the list + * + * @param l + */ + private void removeLink(TLongLink l) { + if (no(l)) + return; + + size--; + + TLongLink prev = l.getPrevious(); + TLongLink next = l.getNext(); + + if (got(prev)) { + prev.setNext(next); + } else { + // No previous we must be head + head = next; + } + + if (got(next)) { + next.setPrevious(prev); + } else { + // No next so me must be tail + tail = prev; + } + // Unlink + l.setNext(null); + l.setPrevious(null); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + if (isEmpty()) + return false; + + for (Object o : collection) { + if (o instanceof Long) { + Long i = (Long) o; + if (!(contains(i))) + return false; + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(TLongCollection collection) { + if (isEmpty()) + return false; + + for (TLongIterator it = collection.iterator(); it.hasNext();) { + long i = it.next(); + if (!(contains(i))) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(long[] array) { + if (isEmpty()) + return false; + + for (long i : array) { + if (!contains(i)) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + boolean ret = false; + for (Long v : collection) { + if (add(v.longValue())) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(TLongCollection collection) { + boolean ret = false; + for (TLongIterator it = collection.iterator(); it.hasNext();) { + long i = it.next(); + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(long[] array) { + boolean ret = false; + for (long i : array) { + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + boolean modified = false; + TLongIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(Long.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(TLongCollection collection) { + boolean modified = false; + TLongIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(long[] array) { + Arrays.sort(array); + + boolean modified = false; + TLongIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) < 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + boolean modified = false; + TLongIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(Long.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(TLongCollection collection) { + boolean modified = false; + TLongIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(long[] array) { + Arrays.sort(array); + + boolean modified = false; + TLongIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) >= 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public long removeAt(int offset) { + TLongLink l = getLinkAt(offset); + if (no(l)) + throw new ArrayIndexOutOfBoundsException("no elemenet at " + offset); + + long prev = l.getValue(); + removeLink(l); + return prev; + } + + /** {@inheritDoc} */ + public void remove(int offset, int length) { + for (int i = 0; i < length; i++) { + removeAt(offset); // since the list shrinks we don't need to use offset+i to get the next entry ;) + } + } + + /** {@inheritDoc} */ + public void transformValues(TLongFunction function) { + for (TLongLink l = head; got(l);) { + // + l.setValue(function.execute(l.getValue())); + // + l = l.getNext(); + } + } + + /** {@inheritDoc} */ + public void reverse() { + TLongLink h = head; + TLongLink t = tail; + TLongLink prev, next, tmp; + + // + TLongLink l = head; + while (got(l)) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // + head = t; + tail = h; + } + + /** {@inheritDoc} */ + public void reverse(int from, int to) { + if (from > to) + throw new IllegalArgumentException("from > to : " + from + ">" + to); + + TLongLink start = getLinkAt(from); + TLongLink stop = getLinkAt(to); + TLongLink prev, next; + TLongLink tmp = null; + + TLongLink tmpHead = start.getPrevious(); + + // + TLongLink l = start; + while (l != stop) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // At this point l == stop and tmp is the but last element { + if (got(tmp)) { + tmpHead.setNext(tmp); + stop.setPrevious(tmpHead); + } + start.setNext(stop); + stop.setPrevious(start); + } + + /** {@inheritDoc} */ + public void shuffle(Random rand) { + for (int i = 0; i < size; i++) { + TLongLink l = getLinkAt(rand.nextInt(size())); + removeLink(l); + add(l.getValue()); + } + } + + /** {@inheritDoc} */ + public TLongList subList(int begin, int end) { + if (end < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than end index " + end); + } + if (size < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than last index " + size); + } + if (begin < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + if (end > size) { + throw new IndexOutOfBoundsException("end index < " + size); + } + + TLongLinkedList ret = new TLongLinkedList(); + TLongLink tmp = getLinkAt(begin); + for (int i = begin; i < end; i++) { + ret.add(tmp.getValue()); // copy + tmp = tmp.getNext(); + } + + return ret; + } + + /** {@inheritDoc} */ + public long[] toArray() { + return toArray(new long[size], 0, size); + } + + /** {@inheritDoc} */ + public long[] toArray(int offset, int len) { + return toArray(new long[len], offset, 0, len); + } + + /** {@inheritDoc} */ + public long[] toArray(long[] dest) { + return toArray(dest, 0, size); + } + + /** {@inheritDoc} */ + public long[] toArray(long[] dest, int offset, int len) { + return toArray(dest, offset, 0, len); + } + + /** {@inheritDoc} */ + public long[] toArray(long[] dest, int source_pos, int dest_pos, int len) { + if (len == 0) { + return dest; // nothing to copy + } + if (source_pos < 0 || source_pos >= size()) { + throw new ArrayIndexOutOfBoundsException(source_pos); + } + + TLongLink tmp = getLinkAt(source_pos); + for (int i = 0; i < len; i++) { + dest[dest_pos + i] = tmp.getValue(); // copy + tmp = tmp.getNext(); + } + + return dest; + } + + /** {@inheritDoc} */ + public boolean forEach(TLongProcedure procedure) { + for (TLongLink l = head; got(l); l = l.getNext()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean forEachDescending(TLongProcedure procedure) { + for (TLongLink l = tail; got(l); l = l.getPrevious()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public void sort() { + sort(0, size); + } + + /** {@inheritDoc} */ + public void sort(int fromIndex, int toIndex) { + TLongList tmp = subList(fromIndex, toIndex); + long[] vals = tmp.toArray(); + Arrays.sort(vals); + set(fromIndex, vals); + } + + /** {@inheritDoc} */ + public void fill(long val) { + fill(0, size, val); + } + + /** {@inheritDoc} */ + public void fill(int fromIndex, int toIndex, long val) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + + TLongLink l = getLinkAt(fromIndex); + if (toIndex > size) { + for (int i = fromIndex; i < size; i++) { + l.setValue(val); + l = l.getNext(); + } + for (int i = size; i < toIndex; i++) { + add(val); + } + } else { + for (int i = fromIndex; i < toIndex; i++) { + l.setValue(val); + l = l.getNext(); + } + } + + } + + /** {@inheritDoc} */ + public int binarySearch(long value) { + return binarySearch(value, 0, size()); + } + + /** {@inheritDoc} */ + public int binarySearch(long value, int fromIndex, int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + if (toIndex > size) { + throw new IndexOutOfBoundsException("end index > size: " + toIndex + " > " + size); + } + + + if (toIndex < fromIndex) { + return -(fromIndex+1); + } + + TLongLink middle; + int mid; + int from = fromIndex; + TLongLink fromLink = getLinkAt(fromIndex); + int to = toIndex; + + while (from < to) { + mid = (from + to) >>> 1; + middle = getLink(fromLink, from, mid); + if (middle.getValue() == value) + return mid; + + if (middle.getValue() < value) { + from = mid + 1; + fromLink = middle.next; + } else { + to = mid - 1; + } + } + + return -(from + 1); + } + + /** {@inheritDoc} */ + public int indexOf(long value) { + return indexOf(0, value); + } + + /** {@inheritDoc} */ + public int indexOf(int offset, long value) { + int count = offset; + + TLongLink l; + for (l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + return count; + + count++; + } + + if ( l != null && l.getValue() == value ) return count; + + return -1; + } + + /** {@inheritDoc} */ + public int lastIndexOf(long value) { + return lastIndexOf(0, value); + } + + /** {@inheritDoc} */ + public int lastIndexOf(int offset, long value) { + if (isEmpty()) + return -1; + + int last = -1; + int count = offset; + for (TLongLink l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + last = count; + + count++; + } + + return last; + } + + /** {@inheritDoc} */ + public boolean contains(long value) { + if (isEmpty()) + return false; + + for (TLongLink l = head; got(l); l = l.getNext()) { + if (l.getValue() == value) + return true; + } + return false; + + } + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongIterator() { + TLongLink l = head; + TLongLink current; + + public long next() { + if (no(l)) + throw new NoSuchElementException(); + + long ret = l.getValue(); + current = l; + l = l.getNext(); + + return ret; + } + + public boolean hasNext() { + return got(l); + } + + public void remove() { + if (current == null) + throw new IllegalStateException(); + + removeLink(current); + current = null; + } + }; + } + + /** {@inheritDoc} */ + public TLongList grep(TLongProcedure condition) { + TLongList ret = new TLongLinkedList(); + for (TLongLink l = head; got(l); l = l.getNext()) { + if (condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public TLongList inverseGrep(TLongProcedure condition) { + TLongList ret = new TLongLinkedList(); + for (TLongLink l = head; got(l); l = l.getNext()) { + if (!condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public long max() { + long ret = Long.MIN_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TLongLink l = head; got(l); l = l.getNext()) { + if (ret < l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public long min() { + long ret = Long.MAX_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TLongLink l = head; got(l); l = l.getNext()) { + if (ret > l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public long sum() { + long sum = 0; + + for (TLongLink l = head; got(l); l = l.getNext()) { + sum += l.getValue(); + } + + return sum; + } + + // + // + // + static class TLongLink { + long value; + TLongLink previous; + TLongLink next; + + TLongLink(long value) { + this.value = value; + } + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } + + public TLongLink getPrevious() { + return previous; + } + + public void setPrevious(TLongLink previous) { + this.previous = previous; + } + + public TLongLink getNext() { + return next; + } + + public void setNext(TLongLink next) { + this.next = next; + } + } + + class RemoveProcedure implements TLongProcedure { + boolean changed = false; + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(long value) { + if (remove(value)) + changed = true; + + return true; + } + + public boolean isChanged() { + return changed; + } + } + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // NO_ENTRY_VALUE + out.writeLong(no_entry_value); + + // ENTRIES + out.writeInt(size); + for (TLongIterator iterator = iterator(); iterator.hasNext();) { + long next = iterator.next(); + out.writeLong(next); + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + + // ENTRIES + int len = in.readInt(); + for (int i = 0; i < len; i++) { + add(in.readLong()); + } + } + + static boolean got(Object ref) { + return ref != null; + } + + static boolean no(Object ref) { + return ref == null; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TLongList ) ) return false; + + TLongList that = ( TLongList )other; + if ( size() != that.size() ) return false; + + for( int i = 0; i < size(); i++ ) { + if ( get( i ) != that.get( i ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = size(); i-- > 0; ) { + h += HashFunctions.hash( get( i ) ); + } + return h; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + TLongIterator it = iterator(); + while (it.hasNext()) { + long next = it.next(); + buf.append(next); + if (it.hasNext()) + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + + } +} // TLongLinkedList diff --git a/src/gnu/trove/list/linked/TShortLinkedList.java b/src/gnu/trove/list/linked/TShortLinkedList.java new file mode 100644 index 0000000..104046b --- /dev/null +++ b/src/gnu/trove/list/linked/TShortLinkedList.java @@ -0,0 +1,1059 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// Copyright (c) 2011, Johan Parent All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.list.linked; + +import gnu.trove.function.TShortFunction; +import gnu.trove.list.TShortList; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.iterator.TShortIterator; +import gnu.trove.TShortCollection; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A resizable, double linked list of short primitives. + */ +public class TShortLinkedList implements TShortList, Externalizable { + private short no_entry_value; + private int size; + + private TShortLink head = null; + private TShortLink tail = head; + + public TShortLinkedList() { + this( Constants.DEFAULT_SHORT_NO_ENTRY_VALUE ); + } + + public TShortLinkedList(short no_entry_value) { + this.no_entry_value = no_entry_value; + } + + public TShortLinkedList(TShortList list) { + no_entry_value = list.getNoEntryValue(); + // + for (TShortIterator iterator = list.iterator(); iterator.hasNext();) { + short next = iterator.next(); + add(next); + } + } + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return size() == 0; + } + + /** {@inheritDoc} */ + public boolean add(short val) { + TShortLink l = new TShortLink(val); + if (no(head)) { + head = l; + tail = l; + } else { + l.setPrevious(tail); + tail.setNext(l); + // + tail = l; + } + + size++; + return true; + } + + /** {@inheritDoc} */ + public void add(short[] vals) { + for (short val : vals) { + add(val); + } + } + + /** {@inheritDoc} */ + public void add(short[] vals, int offset, int length) { + for (int i = 0; i < length; i++) { + short val = vals[offset + i]; + add(val); + } + } + + /** {@inheritDoc} */ + public void insert(int offset, short value) { + TShortLinkedList tmp = new TShortLinkedList(); + tmp.add(value); + insert(offset, tmp); + } + + /** {@inheritDoc} */ + public void insert(int offset, short[] values) { + insert(offset, link(values, 0, values.length)); + } + + /** {@inheritDoc} */ + public void insert(int offset, short[] values, int valOffset, int len) { + insert(offset, link(values, valOffset, len)); + } + + void insert(int offset, TShortLinkedList tmp) { + TShortLink l = getLinkAt(offset); + + size = size + tmp.size; + // + if (l == head) { + // Add in front + tmp.tail.setNext(head); + head.setPrevious(tmp.tail); + head = tmp.head; + + return; + } + + if (no(l)) { + if (size == 0) { + // New empty list + head = tmp.head; + tail = tmp.tail; + } else { + // append + tail.setNext(tmp.head); + tmp.head.setPrevious(tail); + tail = tmp.tail; + } + } else { + TShortLink prev = l.getPrevious(); + l.getPrevious().setNext(tmp.head); + + // Link by behind tmp + tmp.tail.setNext(l); + l.setPrevious(tmp.tail); + + tmp.head.setPrevious(prev); + } + } + + static TShortLinkedList link(short[] values, int valOffset, int len) { + TShortLinkedList ret = new TShortLinkedList(); + + for (int i = 0; i < len; i++) { + ret.add(values[valOffset + i]); + } + + return ret; + } + + /** {@inheritDoc} */ + public short get(int offset) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TShortLink l = getLinkAt(offset); + // + if (no(l)) + return no_entry_value; + + return l.getValue(); + } + + /** + * Returns the link at the given offset. + *

+ * A simple bisection criteria is used to keep the worst case complexity equal to + * O(n/2) where n = size(). Simply start from head of list or tail depending on offset + * and list size. + * + * @param offset of the link + * @return link or null if non-existent + */ + public TShortLink getLinkAt(int offset) { + if (offset >= size()) + return null; + + if (offset <= (size() >>> 1)) + return getLink(head, 0, offset, true); + else + return getLink(tail, size() - 1, offset, false); + } + + /** + * Returns the link at absolute offset starting from given the initial link 'l' at index 'idx' + * + * @param l + * @param idx + * @param offset + * @return + */ + private static TShortLink getLink(TShortLink l, int idx, int offset) { + return getLink(l, idx, offset, true); + } + + /** + * Returns link at given absolute offset starting from link 'l' at index 'idx' + * @param l + * @param idx + * @param offset + * @param next + * @return + */ + private static TShortLink getLink(TShortLink l, int idx, int offset, boolean next) { + int i = idx; + // + while (got(l)) { + if (i == offset) { + return l; + } + + i = i + (next ? 1 : -1); + l = next ? l.getNext() : l.getPrevious(); + } + + return null; + } + + + /** {@inheritDoc} */ + public short set(int offset, short val) { + if (offset > size) + throw new IndexOutOfBoundsException("index " + offset + " exceeds size " + size); + + TShortLink l = getLinkAt(offset); + // + if (no(l)) + throw new IndexOutOfBoundsException("at offset " + offset); + + short prev = l.getValue(); + l.setValue(val); + return prev; + } + + /** {@inheritDoc} */ + public void set(int offset, short[] values) { + set(offset, values, 0, values.length); + } + + /** {@inheritDoc} */ + public void set(int offset, short[] values, int valOffset, int length) { + for (int i = 0; i < length; i++) { + short value = values[valOffset + i]; + set(offset + i, value); + } + } + + /** {@inheritDoc} */ + public short replace(int offset, short val) { + return set(offset, val); + } + + /** {@inheritDoc} */ + public void clear() { + size = 0; + // + head = null; + tail = null; + } + + /** {@inheritDoc} */ + public boolean remove(short value) { + boolean changed = false; + for (TShortLink l = head; got(l); l = l.getNext()) { + // + if (l.getValue() == value) { + changed = true; + // + removeLink(l); + } + } + + return changed; + } + + /** + * unlinks the give TShortLink from the list + * + * @param l + */ + private void removeLink(TShortLink l) { + if (no(l)) + return; + + size--; + + TShortLink prev = l.getPrevious(); + TShortLink next = l.getNext(); + + if (got(prev)) { + prev.setNext(next); + } else { + // No previous we must be head + head = next; + } + + if (got(next)) { + next.setPrevious(prev); + } else { + // No next so me must be tail + tail = prev; + } + // Unlink + l.setNext(null); + l.setPrevious(null); + } + + /** {@inheritDoc} */ + public boolean containsAll(Collection collection) { + if (isEmpty()) + return false; + + for (Object o : collection) { + if (o instanceof Short) { + Short i = (Short) o; + if (!(contains(i))) + return false; + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(TShortCollection collection) { + if (isEmpty()) + return false; + + for (TShortIterator it = collection.iterator(); it.hasNext();) { + short i = it.next(); + if (!(contains(i))) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll(short[] array) { + if (isEmpty()) + return false; + + for (short i : array) { + if (!contains(i)) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll(Collection collection) { + boolean ret = false; + for (Short v : collection) { + if (add(v.shortValue())) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(TShortCollection collection) { + boolean ret = false; + for (TShortIterator it = collection.iterator(); it.hasNext();) { + short i = it.next(); + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean addAll(short[] array) { + boolean ret = false; + for (short i : array) { + if (add(i)) + ret = true; + } + + return ret; + } + + /** {@inheritDoc} */ + public boolean retainAll(Collection collection) { + boolean modified = false; + TShortIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(Short.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(TShortCollection collection) { + boolean modified = false; + TShortIterator iter = iterator(); + while (iter.hasNext()) { + if (!collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll(short[] array) { + Arrays.sort(array); + + boolean modified = false; + TShortIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) < 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(Collection collection) { + boolean modified = false; + TShortIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(Short.valueOf(iter.next()))) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(TShortCollection collection) { + boolean modified = false; + TShortIterator iter = iterator(); + while (iter.hasNext()) { + if (collection.contains(iter.next())) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean removeAll(short[] array) { + Arrays.sort(array); + + boolean modified = false; + TShortIterator iter = iterator(); + while (iter.hasNext()) { + if (Arrays.binarySearch(array, iter.next()) >= 0) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public short removeAt(int offset) { + TShortLink l = getLinkAt(offset); + if (no(l)) + throw new ArrayIndexOutOfBoundsException("no elemenet at " + offset); + + short prev = l.getValue(); + removeLink(l); + return prev; + } + + /** {@inheritDoc} */ + public void remove(int offset, int length) { + for (int i = 0; i < length; i++) { + removeAt(offset); // since the list shrinks we don't need to use offset+i to get the next entry ;) + } + } + + /** {@inheritDoc} */ + public void transformValues(TShortFunction function) { + for (TShortLink l = head; got(l);) { + // + l.setValue(function.execute(l.getValue())); + // + l = l.getNext(); + } + } + + /** {@inheritDoc} */ + public void reverse() { + TShortLink h = head; + TShortLink t = tail; + TShortLink prev, next, tmp; + + // + TShortLink l = head; + while (got(l)) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // + head = t; + tail = h; + } + + /** {@inheritDoc} */ + public void reverse(int from, int to) { + if (from > to) + throw new IllegalArgumentException("from > to : " + from + ">" + to); + + TShortLink start = getLinkAt(from); + TShortLink stop = getLinkAt(to); + TShortLink prev, next; + TShortLink tmp = null; + + TShortLink tmpHead = start.getPrevious(); + + // + TShortLink l = start; + while (l != stop) { + next = l.getNext(); + prev = l.getPrevious(); + // + tmp = l; + l = l.getNext(); + // + tmp.setNext(prev); + tmp.setPrevious(next); + } + + // At this point l == stop and tmp is the but last element { + if (got(tmp)) { + tmpHead.setNext(tmp); + stop.setPrevious(tmpHead); + } + start.setNext(stop); + stop.setPrevious(start); + } + + /** {@inheritDoc} */ + public void shuffle(Random rand) { + for (int i = 0; i < size; i++) { + TShortLink l = getLinkAt(rand.nextInt(size())); + removeLink(l); + add(l.getValue()); + } + } + + /** {@inheritDoc} */ + public TShortList subList(int begin, int end) { + if (end < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than end index " + end); + } + if (size < begin) { + throw new IllegalArgumentException("begin index " + begin + + " greater than last index " + size); + } + if (begin < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + if (end > size) { + throw new IndexOutOfBoundsException("end index < " + size); + } + + TShortLinkedList ret = new TShortLinkedList(); + TShortLink tmp = getLinkAt(begin); + for (int i = begin; i < end; i++) { + ret.add(tmp.getValue()); // copy + tmp = tmp.getNext(); + } + + return ret; + } + + /** {@inheritDoc} */ + public short[] toArray() { + return toArray(new short[size], 0, size); + } + + /** {@inheritDoc} */ + public short[] toArray(int offset, int len) { + return toArray(new short[len], offset, 0, len); + } + + /** {@inheritDoc} */ + public short[] toArray(short[] dest) { + return toArray(dest, 0, size); + } + + /** {@inheritDoc} */ + public short[] toArray(short[] dest, int offset, int len) { + return toArray(dest, offset, 0, len); + } + + /** {@inheritDoc} */ + public short[] toArray(short[] dest, int source_pos, int dest_pos, int len) { + if (len == 0) { + return dest; // nothing to copy + } + if (source_pos < 0 || source_pos >= size()) { + throw new ArrayIndexOutOfBoundsException(source_pos); + } + + TShortLink tmp = getLinkAt(source_pos); + for (int i = 0; i < len; i++) { + dest[dest_pos + i] = tmp.getValue(); // copy + tmp = tmp.getNext(); + } + + return dest; + } + + /** {@inheritDoc} */ + public boolean forEach(TShortProcedure procedure) { + for (TShortLink l = head; got(l); l = l.getNext()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public boolean forEachDescending(TShortProcedure procedure) { + for (TShortLink l = tail; got(l); l = l.getPrevious()) { + if (!procedure.execute(l.getValue())) + return false; + } + return true; + } + + /** {@inheritDoc} */ + public void sort() { + sort(0, size); + } + + /** {@inheritDoc} */ + public void sort(int fromIndex, int toIndex) { + TShortList tmp = subList(fromIndex, toIndex); + short[] vals = tmp.toArray(); + Arrays.sort(vals); + set(fromIndex, vals); + } + + /** {@inheritDoc} */ + public void fill(short val) { + fill(0, size, val); + } + + /** {@inheritDoc} */ + public void fill(int fromIndex, int toIndex, short val) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + + TShortLink l = getLinkAt(fromIndex); + if (toIndex > size) { + for (int i = fromIndex; i < size; i++) { + l.setValue(val); + l = l.getNext(); + } + for (int i = size; i < toIndex; i++) { + add(val); + } + } else { + for (int i = fromIndex; i < toIndex; i++) { + l.setValue(val); + l = l.getNext(); + } + } + + } + + /** {@inheritDoc} */ + public int binarySearch(short value) { + return binarySearch(value, 0, size()); + } + + /** {@inheritDoc} */ + public int binarySearch(short value, int fromIndex, int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("begin index can not be < 0"); + } + + if (toIndex > size) { + throw new IndexOutOfBoundsException("end index > size: " + toIndex + " > " + size); + } + + + if (toIndex < fromIndex) { + return -(fromIndex+1); + } + + TShortLink middle; + int mid; + int from = fromIndex; + TShortLink fromLink = getLinkAt(fromIndex); + int to = toIndex; + + while (from < to) { + mid = (from + to) >>> 1; + middle = getLink(fromLink, from, mid); + if (middle.getValue() == value) + return mid; + + if (middle.getValue() < value) { + from = mid + 1; + fromLink = middle.next; + } else { + to = mid - 1; + } + } + + return -(from + 1); + } + + /** {@inheritDoc} */ + public int indexOf(short value) { + return indexOf(0, value); + } + + /** {@inheritDoc} */ + public int indexOf(int offset, short value) { + int count = offset; + + TShortLink l; + for (l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + return count; + + count++; + } + + if ( l != null && l.getValue() == value ) return count; + + return -1; + } + + /** {@inheritDoc} */ + public int lastIndexOf(short value) { + return lastIndexOf(0, value); + } + + /** {@inheritDoc} */ + public int lastIndexOf(int offset, short value) { + if (isEmpty()) + return -1; + + int last = -1; + int count = offset; + for (TShortLink l = getLinkAt(offset); got(l.getNext()); l = l.getNext()) { + if (l.getValue() == value) + last = count; + + count++; + } + + return last; + } + + /** {@inheritDoc} */ + public boolean contains(short value) { + if (isEmpty()) + return false; + + for (TShortLink l = head; got(l); l = l.getNext()) { + if (l.getValue() == value) + return true; + } + return false; + + } + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortIterator() { + TShortLink l = head; + TShortLink current; + + public short next() { + if (no(l)) + throw new NoSuchElementException(); + + short ret = l.getValue(); + current = l; + l = l.getNext(); + + return ret; + } + + public boolean hasNext() { + return got(l); + } + + public void remove() { + if (current == null) + throw new IllegalStateException(); + + removeLink(current); + current = null; + } + }; + } + + /** {@inheritDoc} */ + public TShortList grep(TShortProcedure condition) { + TShortList ret = new TShortLinkedList(); + for (TShortLink l = head; got(l); l = l.getNext()) { + if (condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public TShortList inverseGrep(TShortProcedure condition) { + TShortList ret = new TShortLinkedList(); + for (TShortLink l = head; got(l); l = l.getNext()) { + if (!condition.execute(l.getValue())) + ret.add(l.getValue()); + } + return ret; + } + + /** {@inheritDoc} */ + public short max() { + short ret = Short.MIN_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TShortLink l = head; got(l); l = l.getNext()) { + if (ret < l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public short min() { + short ret = Short.MAX_VALUE; + + if (isEmpty()) + throw new IllegalStateException(); + + for (TShortLink l = head; got(l); l = l.getNext()) { + if (ret > l.getValue()) + ret = l.getValue(); + } + + return ret; + } + + /** {@inheritDoc} */ + public short sum() { + short sum = 0; + + for (TShortLink l = head; got(l); l = l.getNext()) { + sum += l.getValue(); + } + + return sum; + } + + // + // + // + static class TShortLink { + short value; + TShortLink previous; + TShortLink next; + + TShortLink(short value) { + this.value = value; + } + + public short getValue() { + return value; + } + + public void setValue(short value) { + this.value = value; + } + + public TShortLink getPrevious() { + return previous; + } + + public void setPrevious(TShortLink previous) { + this.previous = previous; + } + + public TShortLink getNext() { + return next; + } + + public void setNext(TShortLink next) { + this.next = next; + } + } + + class RemoveProcedure implements TShortProcedure { + boolean changed = false; + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(short value) { + if (remove(value)) + changed = true; + + return true; + } + + public boolean isChanged() { + return changed; + } + } + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(0); + + // NO_ENTRY_VALUE + out.writeShort(no_entry_value); + + // ENTRIES + out.writeInt(size); + for (TShortIterator iterator = iterator(); iterator.hasNext();) { + short next = iterator.next(); + out.writeShort(next); + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + + // ENTRIES + int len = in.readInt(); + for (int i = 0; i < len; i++) { + add(in.readShort()); + } + } + + static boolean got(Object ref) { + return ref != null; + } + + static boolean no(Object ref) { + return ref == null; + } + + + // comparing + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( other == this ) { + return true; + } + if ( !( other instanceof TShortList ) ) return false; + + TShortList that = ( TShortList )other; + if ( size() != that.size() ) return false; + + for( int i = 0; i < size(); i++ ) { + if ( get( i ) != that.get( i ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int h = 0; + for ( int i = size(); i-- > 0; ) { + h += HashFunctions.hash( get( i ) ); + } + return h; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + TShortIterator it = iterator(); + while (it.hasNext()) { + short next = it.next(); + buf.append(next); + if (it.hasNext()) + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + + } +} // TShortLinkedList diff --git a/src/gnu/trove/map/TByteByteMap.java b/src/gnu/trove/map/TByteByteMap.java new file mode 100644 index 0000000..0f6e65a --- /dev/null +++ b/src/gnu/trove/map/TByteByteMap.java @@ -0,0 +1,301 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.function.*; +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.TByteCollection; + +import java.util.Map; + + +/** + * Interface for a primitive map of byte keys and byte values. + */ +public interface TByteByteMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public byte getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public byte getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an byte value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte put( byte key, byte value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an byte value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte putIfAbsent( byte key, byte value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TByteByteMap map ); + + + /** + * Retrieves the value for key + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte get( byte key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte remove( byte key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TByteSet + * + * @return the keys of the map as a TByteSet + */ + public TByteSet keySet(); + + + /** + * Returns the keys of the map as an array of byte values. + * + * @return the keys of the map as an array of byte values. + */ + public byte[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public byte[] keys( byte[] array ); + + + /** + * Returns the values of the map as a TByteCollection + * + * @return the values of the map as a TByteCollection + */ + public TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public byte[] values( byte[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an byte value + * @return a boolean value + */ + public boolean containsValue( byte val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an byte value + * @return a boolean value + */ + public boolean containsKey( byte key ); + + + /** + * @return a TByteByteIterator with access to this map's keys and values + */ + public TByteByteIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOByteByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteByteProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( byte key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( byte key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( byte key, byte adjust_amount, byte put_amount ); +} diff --git a/src/gnu/trove/map/TByteCharMap.java b/src/gnu/trove/map/TByteCharMap.java new file mode 100644 index 0000000..3e9e976 --- /dev/null +++ b/src/gnu/trove/map/TByteCharMap.java @@ -0,0 +1,301 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.function.*; +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.TCharCollection; + +import java.util.Map; + + +/** + * Interface for a primitive map of byte keys and char values. + */ +public interface TByteCharMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public byte getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public char getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an byte value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char put( byte key, char value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an byte value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char putIfAbsent( byte key, char value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TByteCharMap map ); + + + /** + * Retrieves the value for key + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char get( byte key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char remove( byte key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TByteSet + * + * @return the keys of the map as a TByteSet + */ + public TByteSet keySet(); + + + /** + * Returns the keys of the map as an array of byte values. + * + * @return the keys of the map as an array of byte values. + */ + public byte[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public byte[] keys( byte[] array ); + + + /** + * Returns the values of the map as a TCharCollection + * + * @return the values of the map as a TCharCollection + */ + public TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public char[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public char[] values( char[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an char value + * @return a boolean value + */ + public boolean containsValue( char val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an byte value + * @return a boolean value + */ + public boolean containsKey( byte key ); + + + /** + * @return a TByteCharIterator with access to this map's keys and values + */ + public TByteCharIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOByteCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteCharProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( byte key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( byte key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( byte key, char adjust_amount, char put_amount ); +} diff --git a/src/gnu/trove/map/TByteDoubleMap.java b/src/gnu/trove/map/TByteDoubleMap.java new file mode 100644 index 0000000..58e401c --- /dev/null +++ b/src/gnu/trove/map/TByteDoubleMap.java @@ -0,0 +1,301 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.function.*; +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.TDoubleCollection; + +import java.util.Map; + + +/** + * Interface for a primitive map of byte keys and double values. + */ +public interface TByteDoubleMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public byte getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public double getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an byte value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double put( byte key, double value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an byte value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double putIfAbsent( byte key, double value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TByteDoubleMap map ); + + + /** + * Retrieves the value for key + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double get( byte key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double remove( byte key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TByteSet + * + * @return the keys of the map as a TByteSet + */ + public TByteSet keySet(); + + + /** + * Returns the keys of the map as an array of byte values. + * + * @return the keys of the map as an array of byte values. + */ + public byte[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public byte[] keys( byte[] array ); + + + /** + * Returns the values of the map as a TDoubleCollection + * + * @return the values of the map as a TDoubleCollection + */ + public TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public double[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public double[] values( double[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an double value + * @return a boolean value + */ + public boolean containsValue( double val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an byte value + * @return a boolean value + */ + public boolean containsKey( byte key ); + + + /** + * @return a TByteDoubleIterator with access to this map's keys and values + */ + public TByteDoubleIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOByteDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteDoubleProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( byte key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( byte key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( byte key, double adjust_amount, double put_amount ); +} diff --git a/src/gnu/trove/map/TByteFloatMap.java b/src/gnu/trove/map/TByteFloatMap.java new file mode 100644 index 0000000..f22a3f4 --- /dev/null +++ b/src/gnu/trove/map/TByteFloatMap.java @@ -0,0 +1,301 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.function.*; +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.TFloatCollection; + +import java.util.Map; + + +/** + * Interface for a primitive map of byte keys and float values. + */ +public interface TByteFloatMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public byte getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public float getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an byte value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float put( byte key, float value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an byte value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float putIfAbsent( byte key, float value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TByteFloatMap map ); + + + /** + * Retrieves the value for key + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float get( byte key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float remove( byte key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TByteSet + * + * @return the keys of the map as a TByteSet + */ + public TByteSet keySet(); + + + /** + * Returns the keys of the map as an array of byte values. + * + * @return the keys of the map as an array of byte values. + */ + public byte[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public byte[] keys( byte[] array ); + + + /** + * Returns the values of the map as a TFloatCollection + * + * @return the values of the map as a TFloatCollection + */ + public TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public float[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public float[] values( float[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an float value + * @return a boolean value + */ + public boolean containsValue( float val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an byte value + * @return a boolean value + */ + public boolean containsKey( byte key ); + + + /** + * @return a TByteFloatIterator with access to this map's keys and values + */ + public TByteFloatIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOByteFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteFloatProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( byte key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( byte key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( byte key, float adjust_amount, float put_amount ); +} diff --git a/src/gnu/trove/map/TByteIntMap.java b/src/gnu/trove/map/TByteIntMap.java new file mode 100644 index 0000000..7adf82a --- /dev/null +++ b/src/gnu/trove/map/TByteIntMap.java @@ -0,0 +1,301 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.function.*; +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.TIntCollection; + +import java.util.Map; + + +/** + * Interface for a primitive map of byte keys and int values. + */ +public interface TByteIntMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public byte getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public int getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an byte value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int put( byte key, int value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an byte value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int putIfAbsent( byte key, int value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TByteIntMap map ); + + + /** + * Retrieves the value for key + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int get( byte key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int remove( byte key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TByteSet + * + * @return the keys of the map as a TByteSet + */ + public TByteSet keySet(); + + + /** + * Returns the keys of the map as an array of byte values. + * + * @return the keys of the map as an array of byte values. + */ + public byte[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public byte[] keys( byte[] array ); + + + /** + * Returns the values of the map as a TIntCollection + * + * @return the values of the map as a TIntCollection + */ + public TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public int[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public int[] values( int[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an int value + * @return a boolean value + */ + public boolean containsValue( int val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an byte value + * @return a boolean value + */ + public boolean containsKey( byte key ); + + + /** + * @return a TByteIntIterator with access to this map's keys and values + */ + public TByteIntIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOByteIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteIntProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( byte key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( byte key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( byte key, int adjust_amount, int put_amount ); +} diff --git a/src/gnu/trove/map/TByteLongMap.java b/src/gnu/trove/map/TByteLongMap.java new file mode 100644 index 0000000..392b906 --- /dev/null +++ b/src/gnu/trove/map/TByteLongMap.java @@ -0,0 +1,301 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.function.*; +import gnu.trove.iterator.*; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.TLongCollection; + +import java.util.Map; + + +/** + * Interface for a primitive map of byte keys and long values. + */ +public interface TByteLongMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public byte getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public long getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an byte value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long put( byte key, long value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an byte value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long putIfAbsent( byte key, long value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TByteLongMap map ); + + + /** + * Retrieves the value for key + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long get( byte key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long remove( byte key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TByteSet + * + * @return the keys of the map as a TByteSet + */ + public TByteSet keySet(); + + + /** + * Returns the keys of the map as an array of byte values. + * + * @return the keys of the map as an array of byte values. + */ + public byte[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public byte[] keys( byte[] array ); + + + /** + * Returns the values of the map as a TLongCollection + * + * @return the values of the map as a TLongCollection + */ + public TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public long[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public long[] values( long[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an long value + * @return a boolean value + */ + public boolean containsValue( long val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an byte value + * @return a boolean value + */ + public boolean containsKey( byte key ); + + + /** + * @return a TByteLongIterator with access to this map's keys and values + */ + public TByteLongIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOByteLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteLongProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( byte key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( byte key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( byte key, long adjust_amount, long put_amount ); +} diff --git a/src/gnu/trove/map/TByteObjectMap.java b/src/gnu/trove/map/TByteObjectMap.java new file mode 100644 index 0000000..02c558f --- /dev/null +++ b/src/gnu/trove/map/TByteObjectMap.java @@ -0,0 +1,427 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.iterator.TByteObjectIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TByteObjectProcedure; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TByteSet; + +import java.util.Collection; +import java.util.Map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of byte keys and Object values. + */ +public interface TByteObjectMap { + +// Query Operations + + /** + * Returns the value that represents null in the {@link #keySet()}. + * The default value is generally zero, but can be changed during + * construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + byte getNoEntryKey(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * key.equals(k). (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( byte key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( Object value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the byte value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + V get( byte key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(byte) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an byte value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryKey() + */ + V put( byte key, V value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an byte value to be associated with the specified key + * + * @return the previous value associated with key, or null + * if none was found. + */ + V putIfAbsent( byte key, V value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * key.equals(k), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous byte value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + V remove( byte key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(byte,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TByteObjectMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link TByteSet} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + TByteSet keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + byte[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + byte[] keys( byte[] array ); + + + + /** + * Returns a {@link Collection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection valueCollection(); + + + /** + * Returns the values of the map as an Object array. Note that the array returned + * is typed as an Object[] and may not be cast to a more specific type. See + * {@link #values(V[])} for a version which allows specifically typed arrays. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of byte values. + */ + Object[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of byte values. + */ + V[] values( V[] array ); + + + /** + * Returns a TByteObjectIterator with access to this map's keys and values. + * + * @return a TByteObjectIterator with access to this map's keys and values. + */ + public TByteObjectIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TByteObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteObjectProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteObjectProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TByteShortMap.java b/src/gnu/trove/map/TByteShortMap.java new file mode 100644 index 0000000..bce7f29 --- /dev/null +++ b/src/gnu/trove/map/TByteShortMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TShortFunction; +import gnu.trove.iterator.TByteShortIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TByteShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TByteSet; + + +/** + * Interface for a primitive map of byte keys and short values. + */ +public interface TByteShortMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public byte getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public short getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an byte value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short put( byte key, short value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an byte value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short putIfAbsent( byte key, short value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TByteShortMap map ); + + + /** + * Retrieves the value for key + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short get( byte key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short remove( byte key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TByteSet + * + * @return the keys of the map as a TByteSet + */ + public TByteSet keySet(); + + + /** + * Returns the keys of the map as an array of byte values. + * + * @return the keys of the map as an array of byte values. + */ + public byte[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public byte[] keys( byte[] array ); + + + /** + * Returns the values of the map as a TShortCollection + * + * @return the values of the map as a TShortCollection + */ + public TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public short[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public short[] values( short[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an short value + * @return a boolean value + */ + public boolean containsValue( short val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an byte value + * @return a boolean value + */ + public boolean containsKey( byte key ); + + + /** + * @return a TByteShortIterator with access to this map's keys and values + */ + public TByteShortIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TByteProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOByteShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TByteShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TByteShortProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( byte key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( byte key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( byte key, short adjust_amount, short put_amount ); +} diff --git a/src/gnu/trove/map/TCharByteMap.java b/src/gnu/trove/map/TCharByteMap.java new file mode 100644 index 0000000..5c7b32f --- /dev/null +++ b/src/gnu/trove/map/TCharByteMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TByteFunction; +import gnu.trove.iterator.TCharByteIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TCharByteProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.set.TCharSet; + + +/** + * Interface for a primitive map of char keys and byte values. + */ +public interface TCharByteMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public char getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public byte getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an char value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte put( char key, byte value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an char value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte putIfAbsent( char key, byte value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TCharByteMap map ); + + + /** + * Retrieves the value for key + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte get( char key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte remove( char key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TCharSet + * + * @return the keys of the map as a TCharSet + */ + public TCharSet keySet(); + + + /** + * Returns the keys of the map as an array of char values. + * + * @return the keys of the map as an array of char values. + */ + public char[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public char[] keys( char[] array ); + + + /** + * Returns the values of the map as a TByteCollection + * + * @return the values of the map as a TByteCollection + */ + public TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public byte[] values( byte[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an byte value + * @return a boolean value + */ + public boolean containsValue( byte val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an char value + * @return a boolean value + */ + public boolean containsKey( char key ); + + + /** + * @return a TCharByteIterator with access to this map's keys and values + */ + public TCharByteIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOCharByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharByteProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( char key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( char key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( char key, byte adjust_amount, byte put_amount ); +} diff --git a/src/gnu/trove/map/TCharCharMap.java b/src/gnu/trove/map/TCharCharMap.java new file mode 100644 index 0000000..70f99a3 --- /dev/null +++ b/src/gnu/trove/map/TCharCharMap.java @@ -0,0 +1,302 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TCharFunction; +import gnu.trove.iterator.TCharCharIterator; +import gnu.trove.procedure.TCharCharProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.set.TCharSet; + + +/** + * Interface for a primitive map of char keys and char values. + */ +public interface TCharCharMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public char getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public char getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an char value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char put( char key, char value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an char value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char putIfAbsent( char key, char value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TCharCharMap map ); + + + /** + * Retrieves the value for key + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char get( char key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char remove( char key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TCharSet + * + * @return the keys of the map as a TCharSet + */ + public TCharSet keySet(); + + + /** + * Returns the keys of the map as an array of char values. + * + * @return the keys of the map as an array of char values. + */ + public char[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public char[] keys( char[] array ); + + + /** + * Returns the values of the map as a TCharCollection + * + * @return the values of the map as a TCharCollection + */ + public TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public char[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public char[] values( char[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an char value + * @return a boolean value + */ + public boolean containsValue( char val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an char value + * @return a boolean value + */ + public boolean containsKey( char key ); + + + /** + * @return a TCharCharIterator with access to this map's keys and values + */ + public TCharCharIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOCharCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharCharProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( char key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( char key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( char key, char adjust_amount, char put_amount ); +} diff --git a/src/gnu/trove/map/TCharDoubleMap.java b/src/gnu/trove/map/TCharDoubleMap.java new file mode 100644 index 0000000..ff12c33 --- /dev/null +++ b/src/gnu/trove/map/TCharDoubleMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TDoubleFunction; +import gnu.trove.iterator.TCharDoubleIterator; +import gnu.trove.procedure.TCharDoubleProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TCharSet; + + +/** + * Interface for a primitive map of char keys and double values. + */ +public interface TCharDoubleMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public char getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public double getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an char value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double put( char key, double value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an char value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double putIfAbsent( char key, double value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TCharDoubleMap map ); + + + /** + * Retrieves the value for key + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double get( char key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double remove( char key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TCharSet + * + * @return the keys of the map as a TCharSet + */ + public TCharSet keySet(); + + + /** + * Returns the keys of the map as an array of char values. + * + * @return the keys of the map as an array of char values. + */ + public char[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public char[] keys( char[] array ); + + + /** + * Returns the values of the map as a TDoubleCollection + * + * @return the values of the map as a TDoubleCollection + */ + public TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public double[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public double[] values( double[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an double value + * @return a boolean value + */ + public boolean containsValue( double val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an char value + * @return a boolean value + */ + public boolean containsKey( char key ); + + + /** + * @return a TCharDoubleIterator with access to this map's keys and values + */ + public TCharDoubleIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOCharDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharDoubleProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( char key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( char key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( char key, double adjust_amount, double put_amount ); +} diff --git a/src/gnu/trove/map/TCharFloatMap.java b/src/gnu/trove/map/TCharFloatMap.java new file mode 100644 index 0000000..04e7ef8 --- /dev/null +++ b/src/gnu/trove/map/TCharFloatMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TFloatFunction; +import gnu.trove.iterator.TCharFloatIterator; +import gnu.trove.procedure.TCharFloatProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TCharSet; + + +/** + * Interface for a primitive map of char keys and float values. + */ +public interface TCharFloatMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public char getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public float getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an char value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float put( char key, float value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an char value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float putIfAbsent( char key, float value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TCharFloatMap map ); + + + /** + * Retrieves the value for key + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float get( char key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float remove( char key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TCharSet + * + * @return the keys of the map as a TCharSet + */ + public TCharSet keySet(); + + + /** + * Returns the keys of the map as an array of char values. + * + * @return the keys of the map as an array of char values. + */ + public char[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public char[] keys( char[] array ); + + + /** + * Returns the values of the map as a TFloatCollection + * + * @return the values of the map as a TFloatCollection + */ + public TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public float[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public float[] values( float[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an float value + * @return a boolean value + */ + public boolean containsValue( float val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an char value + * @return a boolean value + */ + public boolean containsKey( char key ); + + + /** + * @return a TCharFloatIterator with access to this map's keys and values + */ + public TCharFloatIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOCharFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharFloatProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( char key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( char key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( char key, float adjust_amount, float put_amount ); +} diff --git a/src/gnu/trove/map/TCharIntMap.java b/src/gnu/trove/map/TCharIntMap.java new file mode 100644 index 0000000..761372a --- /dev/null +++ b/src/gnu/trove/map/TCharIntMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TIntFunction; +import gnu.trove.iterator.TCharIntIterator; +import gnu.trove.procedure.TCharIntProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TCharSet; + + +/** + * Interface for a primitive map of char keys and int values. + */ +public interface TCharIntMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public char getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public int getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an char value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int put( char key, int value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an char value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int putIfAbsent( char key, int value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TCharIntMap map ); + + + /** + * Retrieves the value for key + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int get( char key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int remove( char key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TCharSet + * + * @return the keys of the map as a TCharSet + */ + public TCharSet keySet(); + + + /** + * Returns the keys of the map as an array of char values. + * + * @return the keys of the map as an array of char values. + */ + public char[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public char[] keys( char[] array ); + + + /** + * Returns the values of the map as a TIntCollection + * + * @return the values of the map as a TIntCollection + */ + public TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public int[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public int[] values( int[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an int value + * @return a boolean value + */ + public boolean containsValue( int val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an char value + * @return a boolean value + */ + public boolean containsKey( char key ); + + + /** + * @return a TCharIntIterator with access to this map's keys and values + */ + public TCharIntIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOCharIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharIntProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( char key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( char key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( char key, int adjust_amount, int put_amount ); +} diff --git a/src/gnu/trove/map/TCharLongMap.java b/src/gnu/trove/map/TCharLongMap.java new file mode 100644 index 0000000..1163c7d --- /dev/null +++ b/src/gnu/trove/map/TCharLongMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TLongCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TLongFunction; +import gnu.trove.iterator.TCharLongIterator; +import gnu.trove.procedure.TCharLongProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TCharSet; + + +/** + * Interface for a primitive map of char keys and long values. + */ +public interface TCharLongMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public char getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public long getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an char value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long put( char key, long value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an char value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long putIfAbsent( char key, long value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TCharLongMap map ); + + + /** + * Retrieves the value for key + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long get( char key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long remove( char key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TCharSet + * + * @return the keys of the map as a TCharSet + */ + public TCharSet keySet(); + + + /** + * Returns the keys of the map as an array of char values. + * + * @return the keys of the map as an array of char values. + */ + public char[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public char[] keys( char[] array ); + + + /** + * Returns the values of the map as a TLongCollection + * + * @return the values of the map as a TLongCollection + */ + public TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public long[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public long[] values( long[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an long value + * @return a boolean value + */ + public boolean containsValue( long val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an char value + * @return a boolean value + */ + public boolean containsKey( char key ); + + + /** + * @return a TCharLongIterator with access to this map's keys and values + */ + public TCharLongIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOCharLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharLongProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( char key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( char key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( char key, long adjust_amount, long put_amount ); +} diff --git a/src/gnu/trove/map/TCharObjectMap.java b/src/gnu/trove/map/TCharObjectMap.java new file mode 100644 index 0000000..3927bcc --- /dev/null +++ b/src/gnu/trove/map/TCharObjectMap.java @@ -0,0 +1,427 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.iterator.TCharObjectIterator; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TCharObjectProcedure; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TCharSet; + +import java.util.Collection; +import java.util.Map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of char keys and Object values. + */ +public interface TCharObjectMap { + +// Query Operations + + /** + * Returns the value that represents null in the {@link #keySet()}. + * The default value is generally zero, but can be changed during + * construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + char getNoEntryKey(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * key.equals(k). (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( char key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( Object value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the char value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + V get( char key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(char) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an char value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryKey() + */ + V put( char key, V value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an char value to be associated with the specified key + * + * @return the previous value associated with key, or null + * if none was found. + */ + V putIfAbsent( char key, V value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * key.equals(k), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous char value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + V remove( char key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(char,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TCharObjectMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link TCharSet} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + TCharSet keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + char[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + char[] keys( char[] array ); + + + + /** + * Returns a {@link Collection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection valueCollection(); + + + /** + * Returns the values of the map as an Object array. Note that the array returned + * is typed as an Object[] and may not be cast to a more specific type. See + * {@link #values(V[])} for a version which allows specifically typed arrays. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of char values. + */ + Object[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of char values. + */ + V[] values( V[] array ); + + + /** + * Returns a TCharObjectIterator with access to this map's keys and values. + * + * @return a TCharObjectIterator with access to this map's keys and values. + */ + public TCharObjectIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TCharObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharObjectProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharObjectProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TCharShortMap.java b/src/gnu/trove/map/TCharShortMap.java new file mode 100644 index 0000000..b234dab --- /dev/null +++ b/src/gnu/trove/map/TCharShortMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TShortFunction; +import gnu.trove.iterator.TCharShortIterator; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TCharShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TCharSet; + + +/** + * Interface for a primitive map of char keys and short values. + */ +public interface TCharShortMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public char getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public short getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an char value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short put( char key, short value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an char value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short putIfAbsent( char key, short value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TCharShortMap map ); + + + /** + * Retrieves the value for key + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short get( char key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short remove( char key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TCharSet + * + * @return the keys of the map as a TCharSet + */ + public TCharSet keySet(); + + + /** + * Returns the keys of the map as an array of char values. + * + * @return the keys of the map as an array of char values. + */ + public char[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public char[] keys( char[] array ); + + + /** + * Returns the values of the map as a TShortCollection + * + * @return the values of the map as a TShortCollection + */ + public TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public short[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public short[] values( short[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an short value + * @return a boolean value + */ + public boolean containsValue( short val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an char value + * @return a boolean value + */ + public boolean containsKey( char key ); + + + /** + * @return a TCharShortIterator with access to this map's keys and values + */ + public TCharShortIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TCharProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOCharShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TCharShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TCharShortProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( char key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( char key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( char key, short adjust_amount, short put_amount ); +} diff --git a/src/gnu/trove/map/TDoubleByteMap.java b/src/gnu/trove/map/TDoubleByteMap.java new file mode 100644 index 0000000..d87901c --- /dev/null +++ b/src/gnu/trove/map/TDoubleByteMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TByteFunction; +import gnu.trove.iterator.TDoubleByteIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TDoubleByteProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TDoubleSet; + + +/** + * Interface for a primitive map of double keys and byte values. + */ +public interface TDoubleByteMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public double getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public byte getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an double value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte put( double key, byte value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an double value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte putIfAbsent( double key, byte value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TDoubleByteMap map ); + + + /** + * Retrieves the value for key + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte get( double key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte remove( double key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TDoubleSet + * + * @return the keys of the map as a TDoubleSet + */ + public TDoubleSet keySet(); + + + /** + * Returns the keys of the map as an array of double values. + * + * @return the keys of the map as an array of double values. + */ + public double[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public double[] keys( double[] array ); + + + /** + * Returns the values of the map as a TByteCollection + * + * @return the values of the map as a TByteCollection + */ + public TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public byte[] values( byte[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an byte value + * @return a boolean value + */ + public boolean containsValue( byte val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an double value + * @return a boolean value + */ + public boolean containsKey( double key ); + + + /** + * @return a TDoubleByteIterator with access to this map's keys and values + */ + public TDoubleByteIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TODoubleByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleByteProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( double key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( double key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( double key, byte adjust_amount, byte put_amount ); +} diff --git a/src/gnu/trove/map/TDoubleCharMap.java b/src/gnu/trove/map/TDoubleCharMap.java new file mode 100644 index 0000000..19102be --- /dev/null +++ b/src/gnu/trove/map/TDoubleCharMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TCharFunction; +import gnu.trove.iterator.TDoubleCharIterator; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TDoubleCharProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TDoubleSet; + + +/** + * Interface for a primitive map of double keys and char values. + */ +public interface TDoubleCharMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public double getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public char getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an double value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char put( double key, char value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an double value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char putIfAbsent( double key, char value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TDoubleCharMap map ); + + + /** + * Retrieves the value for key + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char get( double key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char remove( double key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TDoubleSet + * + * @return the keys of the map as a TDoubleSet + */ + public TDoubleSet keySet(); + + + /** + * Returns the keys of the map as an array of double values. + * + * @return the keys of the map as an array of double values. + */ + public double[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public double[] keys( double[] array ); + + + /** + * Returns the values of the map as a TCharCollection + * + * @return the values of the map as a TCharCollection + */ + public TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public char[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public char[] values( char[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an char value + * @return a boolean value + */ + public boolean containsValue( char val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an double value + * @return a boolean value + */ + public boolean containsKey( double key ); + + + /** + * @return a TDoubleCharIterator with access to this map's keys and values + */ + public TDoubleCharIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TODoubleCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleCharProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( double key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( double key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( double key, char adjust_amount, char put_amount ); +} diff --git a/src/gnu/trove/map/TDoubleDoubleMap.java b/src/gnu/trove/map/TDoubleDoubleMap.java new file mode 100644 index 0000000..e08b6ac --- /dev/null +++ b/src/gnu/trove/map/TDoubleDoubleMap.java @@ -0,0 +1,302 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TDoubleFunction; +import gnu.trove.iterator.TDoubleDoubleIterator; +import gnu.trove.procedure.TDoubleDoubleProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TDoubleSet; + + +/** + * Interface for a primitive map of double keys and double values. + */ +public interface TDoubleDoubleMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public double getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public double getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an double value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double put( double key, double value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an double value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double putIfAbsent( double key, double value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TDoubleDoubleMap map ); + + + /** + * Retrieves the value for key + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double get( double key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double remove( double key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TDoubleSet + * + * @return the keys of the map as a TDoubleSet + */ + public TDoubleSet keySet(); + + + /** + * Returns the keys of the map as an array of double values. + * + * @return the keys of the map as an array of double values. + */ + public double[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public double[] keys( double[] array ); + + + /** + * Returns the values of the map as a TDoubleCollection + * + * @return the values of the map as a TDoubleCollection + */ + public TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public double[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public double[] values( double[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an double value + * @return a boolean value + */ + public boolean containsValue( double val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an double value + * @return a boolean value + */ + public boolean containsKey( double key ); + + + /** + * @return a TDoubleDoubleIterator with access to this map's keys and values + */ + public TDoubleDoubleIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TODoubleDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleDoubleProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( double key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( double key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( double key, double adjust_amount, double put_amount ); +} diff --git a/src/gnu/trove/map/TDoubleFloatMap.java b/src/gnu/trove/map/TDoubleFloatMap.java new file mode 100644 index 0000000..c9c908a --- /dev/null +++ b/src/gnu/trove/map/TDoubleFloatMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TFloatFunction; +import gnu.trove.iterator.TDoubleFloatIterator; +import gnu.trove.procedure.TDoubleFloatProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TDoubleSet; + + +/** + * Interface for a primitive map of double keys and float values. + */ +public interface TDoubleFloatMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public double getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public float getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an double value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float put( double key, float value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an double value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float putIfAbsent( double key, float value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TDoubleFloatMap map ); + + + /** + * Retrieves the value for key + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float get( double key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float remove( double key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TDoubleSet + * + * @return the keys of the map as a TDoubleSet + */ + public TDoubleSet keySet(); + + + /** + * Returns the keys of the map as an array of double values. + * + * @return the keys of the map as an array of double values. + */ + public double[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public double[] keys( double[] array ); + + + /** + * Returns the values of the map as a TFloatCollection + * + * @return the values of the map as a TFloatCollection + */ + public TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public float[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public float[] values( float[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an float value + * @return a boolean value + */ + public boolean containsValue( float val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an double value + * @return a boolean value + */ + public boolean containsKey( double key ); + + + /** + * @return a TDoubleFloatIterator with access to this map's keys and values + */ + public TDoubleFloatIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TODoubleFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleFloatProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( double key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( double key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( double key, float adjust_amount, float put_amount ); +} diff --git a/src/gnu/trove/map/TDoubleIntMap.java b/src/gnu/trove/map/TDoubleIntMap.java new file mode 100644 index 0000000..459ceac --- /dev/null +++ b/src/gnu/trove/map/TDoubleIntMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TIntFunction; +import gnu.trove.iterator.TDoubleIntIterator; +import gnu.trove.procedure.TDoubleIntProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TDoubleSet; + + +/** + * Interface for a primitive map of double keys and int values. + */ +public interface TDoubleIntMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public double getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public int getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an double value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int put( double key, int value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an double value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int putIfAbsent( double key, int value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TDoubleIntMap map ); + + + /** + * Retrieves the value for key + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int get( double key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int remove( double key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TDoubleSet + * + * @return the keys of the map as a TDoubleSet + */ + public TDoubleSet keySet(); + + + /** + * Returns the keys of the map as an array of double values. + * + * @return the keys of the map as an array of double values. + */ + public double[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public double[] keys( double[] array ); + + + /** + * Returns the values of the map as a TIntCollection + * + * @return the values of the map as a TIntCollection + */ + public TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public int[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public int[] values( int[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an int value + * @return a boolean value + */ + public boolean containsValue( int val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an double value + * @return a boolean value + */ + public boolean containsKey( double key ); + + + /** + * @return a TDoubleIntIterator with access to this map's keys and values + */ + public TDoubleIntIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TODoubleIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleIntProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( double key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( double key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( double key, int adjust_amount, int put_amount ); +} diff --git a/src/gnu/trove/map/TDoubleLongMap.java b/src/gnu/trove/map/TDoubleLongMap.java new file mode 100644 index 0000000..e65f729 --- /dev/null +++ b/src/gnu/trove/map/TDoubleLongMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TLongCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TLongFunction; +import gnu.trove.iterator.TDoubleLongIterator; +import gnu.trove.procedure.TDoubleLongProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TDoubleSet; + + +/** + * Interface for a primitive map of double keys and long values. + */ +public interface TDoubleLongMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public double getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public long getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an double value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long put( double key, long value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an double value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long putIfAbsent( double key, long value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TDoubleLongMap map ); + + + /** + * Retrieves the value for key + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long get( double key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long remove( double key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TDoubleSet + * + * @return the keys of the map as a TDoubleSet + */ + public TDoubleSet keySet(); + + + /** + * Returns the keys of the map as an array of double values. + * + * @return the keys of the map as an array of double values. + */ + public double[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public double[] keys( double[] array ); + + + /** + * Returns the values of the map as a TLongCollection + * + * @return the values of the map as a TLongCollection + */ + public TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public long[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public long[] values( long[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an long value + * @return a boolean value + */ + public boolean containsValue( long val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an double value + * @return a boolean value + */ + public boolean containsKey( double key ); + + + /** + * @return a TDoubleLongIterator with access to this map's keys and values + */ + public TDoubleLongIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TODoubleLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleLongProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( double key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( double key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( double key, long adjust_amount, long put_amount ); +} diff --git a/src/gnu/trove/map/TDoubleObjectMap.java b/src/gnu/trove/map/TDoubleObjectMap.java new file mode 100644 index 0000000..1ed01a4 --- /dev/null +++ b/src/gnu/trove/map/TDoubleObjectMap.java @@ -0,0 +1,427 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.iterator.TDoubleObjectIterator; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TDoubleObjectProcedure; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TDoubleSet; + +import java.util.Collection; +import java.util.Map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of double keys and Object values. + */ +public interface TDoubleObjectMap { + +// Query Operations + + /** + * Returns the value that represents null in the {@link #keySet()}. + * The default value is generally zero, but can be changed during + * construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + double getNoEntryKey(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * key.equals(k). (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( double key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( Object value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the double value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + V get( double key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(double) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an double value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryKey() + */ + V put( double key, V value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an double value to be associated with the specified key + * + * @return the previous value associated with key, or null + * if none was found. + */ + V putIfAbsent( double key, V value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * key.equals(k), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous double value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + V remove( double key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(double,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TDoubleObjectMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link TDoubleSet} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + TDoubleSet keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + double[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + double[] keys( double[] array ); + + + + /** + * Returns a {@link Collection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection valueCollection(); + + + /** + * Returns the values of the map as an Object array. Note that the array returned + * is typed as an Object[] and may not be cast to a more specific type. See + * {@link #values(V[])} for a version which allows specifically typed arrays. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of double values. + */ + Object[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of double values. + */ + V[] values( V[] array ); + + + /** + * Returns a TDoubleObjectIterator with access to this map's keys and values. + * + * @return a TDoubleObjectIterator with access to this map's keys and values. + */ + public TDoubleObjectIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TDoubleObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleObjectProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleObjectProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TDoubleShortMap.java b/src/gnu/trove/map/TDoubleShortMap.java new file mode 100644 index 0000000..5c14105 --- /dev/null +++ b/src/gnu/trove/map/TDoubleShortMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TShortFunction; +import gnu.trove.iterator.TDoubleShortIterator; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TDoubleShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TDoubleSet; + + +/** + * Interface for a primitive map of double keys and short values. + */ +public interface TDoubleShortMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public double getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public short getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an double value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short put( double key, short value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an double value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short putIfAbsent( double key, short value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TDoubleShortMap map ); + + + /** + * Retrieves the value for key + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short get( double key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short remove( double key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TDoubleSet + * + * @return the keys of the map as a TDoubleSet + */ + public TDoubleSet keySet(); + + + /** + * Returns the keys of the map as an array of double values. + * + * @return the keys of the map as an array of double values. + */ + public double[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public double[] keys( double[] array ); + + + /** + * Returns the values of the map as a TShortCollection + * + * @return the values of the map as a TShortCollection + */ + public TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public short[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public short[] values( short[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an short value + * @return a boolean value + */ + public boolean containsValue( short val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an double value + * @return a boolean value + */ + public boolean containsKey( double key ); + + + /** + * @return a TDoubleShortIterator with access to this map's keys and values + */ + public TDoubleShortIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TODoubleShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TDoubleShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TDoubleShortProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( double key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( double key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( double key, short adjust_amount, short put_amount ); +} diff --git a/src/gnu/trove/map/TFloatByteMap.java b/src/gnu/trove/map/TFloatByteMap.java new file mode 100644 index 0000000..602ba89 --- /dev/null +++ b/src/gnu/trove/map/TFloatByteMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TByteFunction; +import gnu.trove.iterator.TFloatByteIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TFloatByteProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + + +/** + * Interface for a primitive map of float keys and byte values. + */ +public interface TFloatByteMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public float getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public byte getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an float value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte put( float key, byte value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an float value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte putIfAbsent( float key, byte value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TFloatByteMap map ); + + + /** + * Retrieves the value for key + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte get( float key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte remove( float key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TFloatSet + * + * @return the keys of the map as a TFloatSet + */ + public TFloatSet keySet(); + + + /** + * Returns the keys of the map as an array of float values. + * + * @return the keys of the map as an array of float values. + */ + public float[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public float[] keys( float[] array ); + + + /** + * Returns the values of the map as a TByteCollection + * + * @return the values of the map as a TByteCollection + */ + public TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public byte[] values( byte[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an byte value + * @return a boolean value + */ + public boolean containsValue( byte val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an float value + * @return a boolean value + */ + public boolean containsKey( float key ); + + + /** + * @return a TFloatByteIterator with access to this map's keys and values + */ + public TFloatByteIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOFloatByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatByteProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( float key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( float key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( float key, byte adjust_amount, byte put_amount ); +} diff --git a/src/gnu/trove/map/TFloatCharMap.java b/src/gnu/trove/map/TFloatCharMap.java new file mode 100644 index 0000000..c3d365b --- /dev/null +++ b/src/gnu/trove/map/TFloatCharMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TCharFunction; +import gnu.trove.iterator.TFloatCharIterator; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TFloatCharProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + + +/** + * Interface for a primitive map of float keys and char values. + */ +public interface TFloatCharMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public float getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public char getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an float value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char put( float key, char value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an float value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char putIfAbsent( float key, char value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TFloatCharMap map ); + + + /** + * Retrieves the value for key + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char get( float key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char remove( float key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TFloatSet + * + * @return the keys of the map as a TFloatSet + */ + public TFloatSet keySet(); + + + /** + * Returns the keys of the map as an array of float values. + * + * @return the keys of the map as an array of float values. + */ + public float[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public float[] keys( float[] array ); + + + /** + * Returns the values of the map as a TCharCollection + * + * @return the values of the map as a TCharCollection + */ + public TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public char[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public char[] values( char[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an char value + * @return a boolean value + */ + public boolean containsValue( char val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an float value + * @return a boolean value + */ + public boolean containsKey( float key ); + + + /** + * @return a TFloatCharIterator with access to this map's keys and values + */ + public TFloatCharIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOFloatCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatCharProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( float key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( float key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( float key, char adjust_amount, char put_amount ); +} diff --git a/src/gnu/trove/map/TFloatDoubleMap.java b/src/gnu/trove/map/TFloatDoubleMap.java new file mode 100644 index 0000000..30270cb --- /dev/null +++ b/src/gnu/trove/map/TFloatDoubleMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TDoubleFunction; +import gnu.trove.iterator.TFloatDoubleIterator; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TFloatDoubleProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + + +/** + * Interface for a primitive map of float keys and double values. + */ +public interface TFloatDoubleMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public float getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public double getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an float value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double put( float key, double value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an float value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double putIfAbsent( float key, double value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TFloatDoubleMap map ); + + + /** + * Retrieves the value for key + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double get( float key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double remove( float key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TFloatSet + * + * @return the keys of the map as a TFloatSet + */ + public TFloatSet keySet(); + + + /** + * Returns the keys of the map as an array of float values. + * + * @return the keys of the map as an array of float values. + */ + public float[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public float[] keys( float[] array ); + + + /** + * Returns the values of the map as a TDoubleCollection + * + * @return the values of the map as a TDoubleCollection + */ + public TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public double[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public double[] values( double[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an double value + * @return a boolean value + */ + public boolean containsValue( double val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an float value + * @return a boolean value + */ + public boolean containsKey( float key ); + + + /** + * @return a TFloatDoubleIterator with access to this map's keys and values + */ + public TFloatDoubleIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOFloatDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatDoubleProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( float key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( float key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( float key, double adjust_amount, double put_amount ); +} diff --git a/src/gnu/trove/map/TFloatFloatMap.java b/src/gnu/trove/map/TFloatFloatMap.java new file mode 100644 index 0000000..51acd91 --- /dev/null +++ b/src/gnu/trove/map/TFloatFloatMap.java @@ -0,0 +1,302 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TFloatFunction; +import gnu.trove.iterator.TFloatFloatIterator; +import gnu.trove.procedure.TFloatFloatProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + + +/** + * Interface for a primitive map of float keys and float values. + */ +public interface TFloatFloatMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public float getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public float getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an float value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float put( float key, float value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an float value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float putIfAbsent( float key, float value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TFloatFloatMap map ); + + + /** + * Retrieves the value for key + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float get( float key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float remove( float key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TFloatSet + * + * @return the keys of the map as a TFloatSet + */ + public TFloatSet keySet(); + + + /** + * Returns the keys of the map as an array of float values. + * + * @return the keys of the map as an array of float values. + */ + public float[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public float[] keys( float[] array ); + + + /** + * Returns the values of the map as a TFloatCollection + * + * @return the values of the map as a TFloatCollection + */ + public TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public float[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public float[] values( float[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an float value + * @return a boolean value + */ + public boolean containsValue( float val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an float value + * @return a boolean value + */ + public boolean containsKey( float key ); + + + /** + * @return a TFloatFloatIterator with access to this map's keys and values + */ + public TFloatFloatIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOFloatFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatFloatProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( float key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( float key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( float key, float adjust_amount, float put_amount ); +} diff --git a/src/gnu/trove/map/TFloatIntMap.java b/src/gnu/trove/map/TFloatIntMap.java new file mode 100644 index 0000000..6807e5d --- /dev/null +++ b/src/gnu/trove/map/TFloatIntMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TIntFunction; +import gnu.trove.iterator.TFloatIntIterator; +import gnu.trove.procedure.TFloatIntProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TFloatSet; + + +/** + * Interface for a primitive map of float keys and int values. + */ +public interface TFloatIntMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public float getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public int getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an float value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int put( float key, int value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an float value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int putIfAbsent( float key, int value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TFloatIntMap map ); + + + /** + * Retrieves the value for key + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int get( float key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int remove( float key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TFloatSet + * + * @return the keys of the map as a TFloatSet + */ + public TFloatSet keySet(); + + + /** + * Returns the keys of the map as an array of float values. + * + * @return the keys of the map as an array of float values. + */ + public float[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public float[] keys( float[] array ); + + + /** + * Returns the values of the map as a TIntCollection + * + * @return the values of the map as a TIntCollection + */ + public TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public int[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public int[] values( int[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an int value + * @return a boolean value + */ + public boolean containsValue( int val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an float value + * @return a boolean value + */ + public boolean containsKey( float key ); + + + /** + * @return a TFloatIntIterator with access to this map's keys and values + */ + public TFloatIntIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOFloatIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatIntProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( float key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( float key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( float key, int adjust_amount, int put_amount ); +} diff --git a/src/gnu/trove/map/TFloatLongMap.java b/src/gnu/trove/map/TFloatLongMap.java new file mode 100644 index 0000000..c24f69e --- /dev/null +++ b/src/gnu/trove/map/TFloatLongMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TLongCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TLongFunction; +import gnu.trove.iterator.TFloatLongIterator; +import gnu.trove.procedure.TFloatLongProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TFloatSet; + + +/** + * Interface for a primitive map of float keys and long values. + */ +public interface TFloatLongMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public float getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public long getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an float value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long put( float key, long value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an float value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long putIfAbsent( float key, long value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TFloatLongMap map ); + + + /** + * Retrieves the value for key + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long get( float key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long remove( float key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TFloatSet + * + * @return the keys of the map as a TFloatSet + */ + public TFloatSet keySet(); + + + /** + * Returns the keys of the map as an array of float values. + * + * @return the keys of the map as an array of float values. + */ + public float[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public float[] keys( float[] array ); + + + /** + * Returns the values of the map as a TLongCollection + * + * @return the values of the map as a TLongCollection + */ + public TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public long[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public long[] values( long[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an long value + * @return a boolean value + */ + public boolean containsValue( long val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an float value + * @return a boolean value + */ + public boolean containsKey( float key ); + + + /** + * @return a TFloatLongIterator with access to this map's keys and values + */ + public TFloatLongIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOFloatLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatLongProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( float key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( float key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( float key, long adjust_amount, long put_amount ); +} diff --git a/src/gnu/trove/map/TFloatObjectMap.java b/src/gnu/trove/map/TFloatObjectMap.java new file mode 100644 index 0000000..a6e8129 --- /dev/null +++ b/src/gnu/trove/map/TFloatObjectMap.java @@ -0,0 +1,427 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.iterator.TFloatObjectIterator; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TFloatObjectProcedure; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TFloatSet; + +import java.util.Collection; +import java.util.Map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of float keys and Object values. + */ +public interface TFloatObjectMap { + +// Query Operations + + /** + * Returns the value that represents null in the {@link #keySet()}. + * The default value is generally zero, but can be changed during + * construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + float getNoEntryKey(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * key.equals(k). (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( float key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( Object value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the float value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + V get( float key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(float) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an float value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryKey() + */ + V put( float key, V value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an float value to be associated with the specified key + * + * @return the previous value associated with key, or null + * if none was found. + */ + V putIfAbsent( float key, V value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * key.equals(k), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous float value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + V remove( float key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(float,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TFloatObjectMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link TFloatSet} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + TFloatSet keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + float[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + float[] keys( float[] array ); + + + + /** + * Returns a {@link Collection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection valueCollection(); + + + /** + * Returns the values of the map as an Object array. Note that the array returned + * is typed as an Object[] and may not be cast to a more specific type. See + * {@link #values(V[])} for a version which allows specifically typed arrays. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of float values. + */ + Object[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of float values. + */ + V[] values( V[] array ); + + + /** + * Returns a TFloatObjectIterator with access to this map's keys and values. + * + * @return a TFloatObjectIterator with access to this map's keys and values. + */ + public TFloatObjectIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TFloatObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatObjectProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatObjectProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TFloatShortMap.java b/src/gnu/trove/map/TFloatShortMap.java new file mode 100644 index 0000000..61871b4 --- /dev/null +++ b/src/gnu/trove/map/TFloatShortMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TShortFunction; +import gnu.trove.iterator.TFloatShortIterator; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TFloatShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TFloatSet; + + +/** + * Interface for a primitive map of float keys and short values. + */ +public interface TFloatShortMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public float getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public short getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an float value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short put( float key, short value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an float value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short putIfAbsent( float key, short value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TFloatShortMap map ); + + + /** + * Retrieves the value for key + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short get( float key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short remove( float key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TFloatSet + * + * @return the keys of the map as a TFloatSet + */ + public TFloatSet keySet(); + + + /** + * Returns the keys of the map as an array of float values. + * + * @return the keys of the map as an array of float values. + */ + public float[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public float[] keys( float[] array ); + + + /** + * Returns the values of the map as a TShortCollection + * + * @return the values of the map as a TShortCollection + */ + public TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public short[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public short[] values( short[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an short value + * @return a boolean value + */ + public boolean containsValue( short val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an float value + * @return a boolean value + */ + public boolean containsKey( float key ); + + + /** + * @return a TFloatShortIterator with access to this map's keys and values + */ + public TFloatShortIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TFloatProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOFloatShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TFloatShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TFloatShortProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( float key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( float key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( float key, short adjust_amount, short put_amount ); +} diff --git a/src/gnu/trove/map/TIntByteMap.java b/src/gnu/trove/map/TIntByteMap.java new file mode 100644 index 0000000..bdc1e6b --- /dev/null +++ b/src/gnu/trove/map/TIntByteMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TByteFunction; +import gnu.trove.iterator.TIntByteIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TIntByteProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + + +/** + * Interface for a primitive map of int keys and byte values. + */ +public interface TIntByteMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public int getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public byte getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an int value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte put( int key, byte value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an int value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte putIfAbsent( int key, byte value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TIntByteMap map ); + + + /** + * Retrieves the value for key + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte get( int key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte remove( int key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TIntSet + * + * @return the keys of the map as a TIntSet + */ + public TIntSet keySet(); + + + /** + * Returns the keys of the map as an array of int values. + * + * @return the keys of the map as an array of int values. + */ + public int[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public int[] keys( int[] array ); + + + /** + * Returns the values of the map as a TByteCollection + * + * @return the values of the map as a TByteCollection + */ + public TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public byte[] values( byte[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an byte value + * @return a boolean value + */ + public boolean containsValue( byte val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an int value + * @return a boolean value + */ + public boolean containsKey( int key ); + + + /** + * @return a TIntByteIterator with access to this map's keys and values + */ + public TIntByteIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOIntByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntByteProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( int key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( int key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( int key, byte adjust_amount, byte put_amount ); +} diff --git a/src/gnu/trove/map/TIntCharMap.java b/src/gnu/trove/map/TIntCharMap.java new file mode 100644 index 0000000..d6d4abe --- /dev/null +++ b/src/gnu/trove/map/TIntCharMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TCharFunction; +import gnu.trove.iterator.TIntCharIterator; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TIntCharProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + + +/** + * Interface for a primitive map of int keys and char values. + */ +public interface TIntCharMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public int getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public char getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an int value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char put( int key, char value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an int value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char putIfAbsent( int key, char value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TIntCharMap map ); + + + /** + * Retrieves the value for key + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char get( int key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char remove( int key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TIntSet + * + * @return the keys of the map as a TIntSet + */ + public TIntSet keySet(); + + + /** + * Returns the keys of the map as an array of int values. + * + * @return the keys of the map as an array of int values. + */ + public int[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public int[] keys( int[] array ); + + + /** + * Returns the values of the map as a TCharCollection + * + * @return the values of the map as a TCharCollection + */ + public TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public char[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public char[] values( char[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an char value + * @return a boolean value + */ + public boolean containsValue( char val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an int value + * @return a boolean value + */ + public boolean containsKey( int key ); + + + /** + * @return a TIntCharIterator with access to this map's keys and values + */ + public TIntCharIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOIntCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntCharProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( int key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( int key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( int key, char adjust_amount, char put_amount ); +} diff --git a/src/gnu/trove/map/TIntDoubleMap.java b/src/gnu/trove/map/TIntDoubleMap.java new file mode 100644 index 0000000..f1f7722 --- /dev/null +++ b/src/gnu/trove/map/TIntDoubleMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TDoubleFunction; +import gnu.trove.iterator.TIntDoubleIterator; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TIntDoubleProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + + +/** + * Interface for a primitive map of int keys and double values. + */ +public interface TIntDoubleMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public int getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public double getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an int value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double put( int key, double value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an int value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double putIfAbsent( int key, double value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TIntDoubleMap map ); + + + /** + * Retrieves the value for key + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double get( int key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double remove( int key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TIntSet + * + * @return the keys of the map as a TIntSet + */ + public TIntSet keySet(); + + + /** + * Returns the keys of the map as an array of int values. + * + * @return the keys of the map as an array of int values. + */ + public int[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public int[] keys( int[] array ); + + + /** + * Returns the values of the map as a TDoubleCollection + * + * @return the values of the map as a TDoubleCollection + */ + public TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public double[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public double[] values( double[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an double value + * @return a boolean value + */ + public boolean containsValue( double val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an int value + * @return a boolean value + */ + public boolean containsKey( int key ); + + + /** + * @return a TIntDoubleIterator with access to this map's keys and values + */ + public TIntDoubleIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOIntDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntDoubleProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( int key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( int key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( int key, double adjust_amount, double put_amount ); +} diff --git a/src/gnu/trove/map/TIntFloatMap.java b/src/gnu/trove/map/TIntFloatMap.java new file mode 100644 index 0000000..503bf29 --- /dev/null +++ b/src/gnu/trove/map/TIntFloatMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TFloatFunction; +import gnu.trove.iterator.TIntFloatIterator; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TIntFloatProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + + +/** + * Interface for a primitive map of int keys and float values. + */ +public interface TIntFloatMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public int getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public float getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an int value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float put( int key, float value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an int value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float putIfAbsent( int key, float value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TIntFloatMap map ); + + + /** + * Retrieves the value for key + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float get( int key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float remove( int key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TIntSet + * + * @return the keys of the map as a TIntSet + */ + public TIntSet keySet(); + + + /** + * Returns the keys of the map as an array of int values. + * + * @return the keys of the map as an array of int values. + */ + public int[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public int[] keys( int[] array ); + + + /** + * Returns the values of the map as a TFloatCollection + * + * @return the values of the map as a TFloatCollection + */ + public TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public float[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public float[] values( float[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an float value + * @return a boolean value + */ + public boolean containsValue( float val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an int value + * @return a boolean value + */ + public boolean containsKey( int key ); + + + /** + * @return a TIntFloatIterator with access to this map's keys and values + */ + public TIntFloatIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOIntFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntFloatProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( int key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( int key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( int key, float adjust_amount, float put_amount ); +} diff --git a/src/gnu/trove/map/TIntIntMap.java b/src/gnu/trove/map/TIntIntMap.java new file mode 100644 index 0000000..22ff0c7 --- /dev/null +++ b/src/gnu/trove/map/TIntIntMap.java @@ -0,0 +1,302 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TIntFunction; +import gnu.trove.iterator.TIntIntIterator; +import gnu.trove.procedure.TIntIntProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + + +/** + * Interface for a primitive map of int keys and int values. + */ +public interface TIntIntMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public int getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public int getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an int value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int put( int key, int value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an int value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int putIfAbsent( int key, int value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TIntIntMap map ); + + + /** + * Retrieves the value for key + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int get( int key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int remove( int key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TIntSet + * + * @return the keys of the map as a TIntSet + */ + public TIntSet keySet(); + + + /** + * Returns the keys of the map as an array of int values. + * + * @return the keys of the map as an array of int values. + */ + public int[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public int[] keys( int[] array ); + + + /** + * Returns the values of the map as a TIntCollection + * + * @return the values of the map as a TIntCollection + */ + public TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public int[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public int[] values( int[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an int value + * @return a boolean value + */ + public boolean containsValue( int val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an int value + * @return a boolean value + */ + public boolean containsKey( int key ); + + + /** + * @return a TIntIntIterator with access to this map's keys and values + */ + public TIntIntIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOIntIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntIntProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( int key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( int key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( int key, int adjust_amount, int put_amount ); +} diff --git a/src/gnu/trove/map/TIntLongMap.java b/src/gnu/trove/map/TIntLongMap.java new file mode 100644 index 0000000..23b3bd2 --- /dev/null +++ b/src/gnu/trove/map/TIntLongMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TLongCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TLongFunction; +import gnu.trove.iterator.TIntLongIterator; +import gnu.trove.procedure.TIntLongProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TIntSet; + + +/** + * Interface for a primitive map of int keys and long values. + */ +public interface TIntLongMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public int getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public long getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an int value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long put( int key, long value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an int value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long putIfAbsent( int key, long value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TIntLongMap map ); + + + /** + * Retrieves the value for key + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long get( int key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long remove( int key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TIntSet + * + * @return the keys of the map as a TIntSet + */ + public TIntSet keySet(); + + + /** + * Returns the keys of the map as an array of int values. + * + * @return the keys of the map as an array of int values. + */ + public int[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public int[] keys( int[] array ); + + + /** + * Returns the values of the map as a TLongCollection + * + * @return the values of the map as a TLongCollection + */ + public TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public long[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public long[] values( long[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an long value + * @return a boolean value + */ + public boolean containsValue( long val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an int value + * @return a boolean value + */ + public boolean containsKey( int key ); + + + /** + * @return a TIntLongIterator with access to this map's keys and values + */ + public TIntLongIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOIntLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntLongProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( int key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( int key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( int key, long adjust_amount, long put_amount ); +} diff --git a/src/gnu/trove/map/TIntObjectMap.java b/src/gnu/trove/map/TIntObjectMap.java new file mode 100644 index 0000000..94bb353 --- /dev/null +++ b/src/gnu/trove/map/TIntObjectMap.java @@ -0,0 +1,427 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.iterator.TIntObjectIterator; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TIntObjectProcedure; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TIntSet; + +import java.util.Collection; +import java.util.Map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of int keys and Object values. + */ +public interface TIntObjectMap { + +// Query Operations + + /** + * Returns the value that represents null in the {@link #keySet()}. + * The default value is generally zero, but can be changed during + * construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + int getNoEntryKey(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * key.equals(k). (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( int key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( Object value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the int value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + V get( int key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(int) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an int value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryKey() + */ + V put( int key, V value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an int value to be associated with the specified key + * + * @return the previous value associated with key, or null + * if none was found. + */ + V putIfAbsent( int key, V value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * key.equals(k), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous int value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + V remove( int key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(int,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TIntObjectMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link TIntSet} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + TIntSet keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + int[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + int[] keys( int[] array ); + + + + /** + * Returns a {@link Collection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection valueCollection(); + + + /** + * Returns the values of the map as an Object array. Note that the array returned + * is typed as an Object[] and may not be cast to a more specific type. See + * {@link #values(V[])} for a version which allows specifically typed arrays. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of int values. + */ + Object[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of int values. + */ + V[] values( V[] array ); + + + /** + * Returns a TIntObjectIterator with access to this map's keys and values. + * + * @return a TIntObjectIterator with access to this map's keys and values. + */ + public TIntObjectIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TIntObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntObjectProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntObjectProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TIntShortMap.java b/src/gnu/trove/map/TIntShortMap.java new file mode 100644 index 0000000..4779bc8 --- /dev/null +++ b/src/gnu/trove/map/TIntShortMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TShortFunction; +import gnu.trove.iterator.TIntShortIterator; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TIntShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TIntSet; + + +/** + * Interface for a primitive map of int keys and short values. + */ +public interface TIntShortMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public int getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public short getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an int value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short put( int key, short value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an int value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short putIfAbsent( int key, short value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TIntShortMap map ); + + + /** + * Retrieves the value for key + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short get( int key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short remove( int key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TIntSet + * + * @return the keys of the map as a TIntSet + */ + public TIntSet keySet(); + + + /** + * Returns the keys of the map as an array of int values. + * + * @return the keys of the map as an array of int values. + */ + public int[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public int[] keys( int[] array ); + + + /** + * Returns the values of the map as a TShortCollection + * + * @return the values of the map as a TShortCollection + */ + public TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public short[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public short[] values( short[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an short value + * @return a boolean value + */ + public boolean containsValue( short val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an int value + * @return a boolean value + */ + public boolean containsKey( int key ); + + + /** + * @return a TIntShortIterator with access to this map's keys and values + */ + public TIntShortIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TIntProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOIntShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TIntShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TIntShortProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( int key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( int key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( int key, short adjust_amount, short put_amount ); +} diff --git a/src/gnu/trove/map/TLongByteMap.java b/src/gnu/trove/map/TLongByteMap.java new file mode 100644 index 0000000..9a83f08 --- /dev/null +++ b/src/gnu/trove/map/TLongByteMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TByteFunction; +import gnu.trove.iterator.TLongByteIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TLongByteProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TLongSet; + + +/** + * Interface for a primitive map of long keys and byte values. + */ +public interface TLongByteMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public long getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public byte getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an long value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte put( long key, byte value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an long value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte putIfAbsent( long key, byte value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TLongByteMap map ); + + + /** + * Retrieves the value for key + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte get( long key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte remove( long key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TLongSet + * + * @return the keys of the map as a TLongSet + */ + public TLongSet keySet(); + + + /** + * Returns the keys of the map as an array of long values. + * + * @return the keys of the map as an array of long values. + */ + public long[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public long[] keys( long[] array ); + + + /** + * Returns the values of the map as a TByteCollection + * + * @return the values of the map as a TByteCollection + */ + public TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public byte[] values( byte[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an byte value + * @return a boolean value + */ + public boolean containsValue( byte val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an long value + * @return a boolean value + */ + public boolean containsKey( long key ); + + + /** + * @return a TLongByteIterator with access to this map's keys and values + */ + public TLongByteIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOLongByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongByteProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( long key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( long key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( long key, byte adjust_amount, byte put_amount ); +} diff --git a/src/gnu/trove/map/TLongCharMap.java b/src/gnu/trove/map/TLongCharMap.java new file mode 100644 index 0000000..f45597d --- /dev/null +++ b/src/gnu/trove/map/TLongCharMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TCharFunction; +import gnu.trove.iterator.TLongCharIterator; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TLongCharProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TLongSet; + + +/** + * Interface for a primitive map of long keys and char values. + */ +public interface TLongCharMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public long getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public char getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an long value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char put( long key, char value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an long value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char putIfAbsent( long key, char value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TLongCharMap map ); + + + /** + * Retrieves the value for key + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char get( long key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char remove( long key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TLongSet + * + * @return the keys of the map as a TLongSet + */ + public TLongSet keySet(); + + + /** + * Returns the keys of the map as an array of long values. + * + * @return the keys of the map as an array of long values. + */ + public long[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public long[] keys( long[] array ); + + + /** + * Returns the values of the map as a TCharCollection + * + * @return the values of the map as a TCharCollection + */ + public TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public char[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public char[] values( char[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an char value + * @return a boolean value + */ + public boolean containsValue( char val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an long value + * @return a boolean value + */ + public boolean containsKey( long key ); + + + /** + * @return a TLongCharIterator with access to this map's keys and values + */ + public TLongCharIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOLongCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongCharProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( long key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( long key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( long key, char adjust_amount, char put_amount ); +} diff --git a/src/gnu/trove/map/TLongDoubleMap.java b/src/gnu/trove/map/TLongDoubleMap.java new file mode 100644 index 0000000..9f505b2 --- /dev/null +++ b/src/gnu/trove/map/TLongDoubleMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TDoubleFunction; +import gnu.trove.iterator.TLongDoubleIterator; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TLongDoubleProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TLongSet; + + +/** + * Interface for a primitive map of long keys and double values. + */ +public interface TLongDoubleMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public long getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public double getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an long value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double put( long key, double value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an long value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double putIfAbsent( long key, double value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TLongDoubleMap map ); + + + /** + * Retrieves the value for key + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double get( long key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double remove( long key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TLongSet + * + * @return the keys of the map as a TLongSet + */ + public TLongSet keySet(); + + + /** + * Returns the keys of the map as an array of long values. + * + * @return the keys of the map as an array of long values. + */ + public long[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public long[] keys( long[] array ); + + + /** + * Returns the values of the map as a TDoubleCollection + * + * @return the values of the map as a TDoubleCollection + */ + public TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public double[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public double[] values( double[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an double value + * @return a boolean value + */ + public boolean containsValue( double val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an long value + * @return a boolean value + */ + public boolean containsKey( long key ); + + + /** + * @return a TLongDoubleIterator with access to this map's keys and values + */ + public TLongDoubleIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOLongDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongDoubleProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( long key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( long key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( long key, double adjust_amount, double put_amount ); +} diff --git a/src/gnu/trove/map/TLongFloatMap.java b/src/gnu/trove/map/TLongFloatMap.java new file mode 100644 index 0000000..aae6535 --- /dev/null +++ b/src/gnu/trove/map/TLongFloatMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TFloatFunction; +import gnu.trove.iterator.TLongFloatIterator; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TLongFloatProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TLongSet; + + +/** + * Interface for a primitive map of long keys and float values. + */ +public interface TLongFloatMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public long getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public float getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an long value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float put( long key, float value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an long value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float putIfAbsent( long key, float value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TLongFloatMap map ); + + + /** + * Retrieves the value for key + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float get( long key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float remove( long key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TLongSet + * + * @return the keys of the map as a TLongSet + */ + public TLongSet keySet(); + + + /** + * Returns the keys of the map as an array of long values. + * + * @return the keys of the map as an array of long values. + */ + public long[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public long[] keys( long[] array ); + + + /** + * Returns the values of the map as a TFloatCollection + * + * @return the values of the map as a TFloatCollection + */ + public TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public float[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public float[] values( float[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an float value + * @return a boolean value + */ + public boolean containsValue( float val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an long value + * @return a boolean value + */ + public boolean containsKey( long key ); + + + /** + * @return a TLongFloatIterator with access to this map's keys and values + */ + public TLongFloatIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOLongFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongFloatProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( long key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( long key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( long key, float adjust_amount, float put_amount ); +} diff --git a/src/gnu/trove/map/TLongIntMap.java b/src/gnu/trove/map/TLongIntMap.java new file mode 100644 index 0000000..bf58b7a --- /dev/null +++ b/src/gnu/trove/map/TLongIntMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TIntFunction; +import gnu.trove.iterator.TLongIntIterator; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TLongIntProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TLongSet; + + +/** + * Interface for a primitive map of long keys and int values. + */ +public interface TLongIntMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public long getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public int getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an long value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int put( long key, int value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an long value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int putIfAbsent( long key, int value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TLongIntMap map ); + + + /** + * Retrieves the value for key + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int get( long key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int remove( long key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TLongSet + * + * @return the keys of the map as a TLongSet + */ + public TLongSet keySet(); + + + /** + * Returns the keys of the map as an array of long values. + * + * @return the keys of the map as an array of long values. + */ + public long[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public long[] keys( long[] array ); + + + /** + * Returns the values of the map as a TIntCollection + * + * @return the values of the map as a TIntCollection + */ + public TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public int[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public int[] values( int[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an int value + * @return a boolean value + */ + public boolean containsValue( int val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an long value + * @return a boolean value + */ + public boolean containsKey( long key ); + + + /** + * @return a TLongIntIterator with access to this map's keys and values + */ + public TLongIntIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOLongIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongIntProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( long key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( long key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( long key, int adjust_amount, int put_amount ); +} diff --git a/src/gnu/trove/map/TLongLongMap.java b/src/gnu/trove/map/TLongLongMap.java new file mode 100644 index 0000000..a1586ff --- /dev/null +++ b/src/gnu/trove/map/TLongLongMap.java @@ -0,0 +1,302 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TLongCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TLongFunction; +import gnu.trove.iterator.TLongLongIterator; +import gnu.trove.procedure.TLongLongProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TLongSet; + + +/** + * Interface for a primitive map of long keys and long values. + */ +public interface TLongLongMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public long getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public long getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an long value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long put( long key, long value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an long value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long putIfAbsent( long key, long value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TLongLongMap map ); + + + /** + * Retrieves the value for key + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long get( long key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long remove( long key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TLongSet + * + * @return the keys of the map as a TLongSet + */ + public TLongSet keySet(); + + + /** + * Returns the keys of the map as an array of long values. + * + * @return the keys of the map as an array of long values. + */ + public long[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public long[] keys( long[] array ); + + + /** + * Returns the values of the map as a TLongCollection + * + * @return the values of the map as a TLongCollection + */ + public TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public long[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public long[] values( long[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an long value + * @return a boolean value + */ + public boolean containsValue( long val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an long value + * @return a boolean value + */ + public boolean containsKey( long key ); + + + /** + * @return a TLongLongIterator with access to this map's keys and values + */ + public TLongLongIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOLongLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongLongProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( long key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( long key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( long key, long adjust_amount, long put_amount ); +} diff --git a/src/gnu/trove/map/TLongObjectMap.java b/src/gnu/trove/map/TLongObjectMap.java new file mode 100644 index 0000000..f9e5183 --- /dev/null +++ b/src/gnu/trove/map/TLongObjectMap.java @@ -0,0 +1,427 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.iterator.TLongObjectIterator; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TLongObjectProcedure; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TLongSet; + +import java.util.Collection; +import java.util.Map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of long keys and Object values. + */ +public interface TLongObjectMap { + +// Query Operations + + /** + * Returns the value that represents null in the {@link #keySet()}. + * The default value is generally zero, but can be changed during + * construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + long getNoEntryKey(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * key.equals(k). (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( long key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( Object value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the long value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + V get( long key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(long) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an long value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryKey() + */ + V put( long key, V value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an long value to be associated with the specified key + * + * @return the previous value associated with key, or null + * if none was found. + */ + V putIfAbsent( long key, V value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * key.equals(k), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous long value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + V remove( long key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(long,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TLongObjectMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link TLongSet} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + TLongSet keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + long[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + long[] keys( long[] array ); + + + + /** + * Returns a {@link Collection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection valueCollection(); + + + /** + * Returns the values of the map as an Object array. Note that the array returned + * is typed as an Object[] and may not be cast to a more specific type. See + * {@link #values(V[])} for a version which allows specifically typed arrays. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of long values. + */ + Object[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of long values. + */ + V[] values( V[] array ); + + + /** + * Returns a TLongObjectIterator with access to this map's keys and values. + * + * @return a TLongObjectIterator with access to this map's keys and values. + */ + public TLongObjectIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TLongObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongObjectProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongObjectProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TLongShortMap.java b/src/gnu/trove/map/TLongShortMap.java new file mode 100644 index 0000000..00ba82d --- /dev/null +++ b/src/gnu/trove/map/TLongShortMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TShortFunction; +import gnu.trove.iterator.TLongShortIterator; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.procedure.TLongShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TLongSet; + + +/** + * Interface for a primitive map of long keys and short values. + */ +public interface TLongShortMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public long getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public short getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an long value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short put( long key, short value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an long value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short putIfAbsent( long key, short value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TLongShortMap map ); + + + /** + * Retrieves the value for key + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short get( long key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short remove( long key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TLongSet + * + * @return the keys of the map as a TLongSet + */ + public TLongSet keySet(); + + + /** + * Returns the keys of the map as an array of long values. + * + * @return the keys of the map as an array of long values. + */ + public long[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public long[] keys( long[] array ); + + + /** + * Returns the values of the map as a TShortCollection + * + * @return the values of the map as a TShortCollection + */ + public TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public short[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public short[] values( short[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an short value + * @return a boolean value + */ + public boolean containsValue( short val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an long value + * @return a boolean value + */ + public boolean containsKey( long key ); + + + /** + * @return a TLongShortIterator with access to this map's keys and values + */ + public TLongShortIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TLongProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOLongShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TLongShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TLongShortProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( long key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( long key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( long key, short adjust_amount, short put_amount ); +} diff --git a/src/gnu/trove/map/TMap.java b/src/gnu/trove/map/TMap.java new file mode 100644 index 0000000..dec0508 --- /dev/null +++ b/src/gnu/trove/map/TMap.java @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2011, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.function.TObjectFunction; +import gnu.trove.procedure.TObjectObjectProcedure; +import gnu.trove.procedure.TObjectProcedure; + +import java.util.Map; + + +/** + * Interface extension to {@link Map} which adds Trove-specific features. + */ +public interface TMap extends Map { + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or {@code null} if none was found. + */ + public V putIfAbsent(K key, V value); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey(TObjectProcedure procedure); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue(TObjectProcedure procedure); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TObjectObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({}) + public boolean forEachEntry(TObjectObjectProcedure procedure); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings({}) + public boolean retainEntries(TObjectObjectProcedure procedure); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues(TObjectFunction function); +} diff --git a/src/gnu/trove/map/TObjectByteMap.java b/src/gnu/trove/map/TObjectByteMap.java new file mode 100644 index 0000000..6fe7ca1 --- /dev/null +++ b/src/gnu/trove/map/TObjectByteMap.java @@ -0,0 +1,460 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.TByteCollection; +import gnu.trove.function.TByteFunction; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TObjectByteProcedure; +import gnu.trove.iterator.TObjectByteIterator; + +import java.util.Map; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of Object keys and byte values. + */ +public interface TObjectByteMap { + + // Query Operations + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + byte getNoEntryValue(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( Object key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==no_entry_value ? v==no_entry_value : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + *

+ * Note that no_entry_value is the result of {@link #getNoEntryValue()} and represents + * null for this map instance. + * + * @param value byte value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( byte value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the byte value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + byte get( Object key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an byte value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryValue() + */ + byte put( K key, byte value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an byte value to be associated with the specified key + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + byte putIfAbsent( K key, byte value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous byte value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + byte remove( Object key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,byte) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TObjectByteMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + Object[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + K[] keys( K[] array ); + + + + /** + * Returns a {@link TByteCollection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the TByteIterator.remove, + * TByteCollection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of byte values. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of byte values. + */ + byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of byte values. + */ + byte[] values( byte[] array ); + + + /** + * Returns a TObjectByteIterator with access to this map's keys and values. + * + * @return a TObjectByteIterator with access to this map's keys and values. + */ + public TObjectByteIterator iterator(); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( K key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( K key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( K key, byte adjust_amount, byte put_amount ); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TObjectByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TObjectByteProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TObjectCharMap.java b/src/gnu/trove/map/TObjectCharMap.java new file mode 100644 index 0000000..64469b4 --- /dev/null +++ b/src/gnu/trove/map/TObjectCharMap.java @@ -0,0 +1,460 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.TCharCollection; +import gnu.trove.function.TCharFunction; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TObjectCharProcedure; +import gnu.trove.iterator.TObjectCharIterator; + +import java.util.Map; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of Object keys and char values. + */ +public interface TObjectCharMap { + + // Query Operations + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + char getNoEntryValue(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( Object key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==no_entry_value ? v==no_entry_value : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + *

+ * Note that no_entry_value is the result of {@link #getNoEntryValue()} and represents + * null for this map instance. + * + * @param value char value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( char value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the char value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + char get( Object key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an char value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryValue() + */ + char put( K key, char value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an char value to be associated with the specified key + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + char putIfAbsent( K key, char value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous char value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + char remove( Object key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,char) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TObjectCharMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + Object[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + K[] keys( K[] array ); + + + + /** + * Returns a {@link TCharCollection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the TCharIterator.remove, + * TCharCollection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of char values. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of char values. + */ + char[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of char values. + */ + char[] values( char[] array ); + + + /** + * Returns a TObjectCharIterator with access to this map's keys and values. + * + * @return a TObjectCharIterator with access to this map's keys and values. + */ + public TObjectCharIterator iterator(); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( K key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( K key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( K key, char adjust_amount, char put_amount ); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TObjectCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TObjectCharProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TObjectDoubleMap.java b/src/gnu/trove/map/TObjectDoubleMap.java new file mode 100644 index 0000000..59059c5 --- /dev/null +++ b/src/gnu/trove/map/TObjectDoubleMap.java @@ -0,0 +1,460 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TObjectDoubleProcedure; +import gnu.trove.iterator.TObjectDoubleIterator; + +import java.util.Map; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of Object keys and double values. + */ +public interface TObjectDoubleMap { + + // Query Operations + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + double getNoEntryValue(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( Object key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==no_entry_value ? v==no_entry_value : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + *

+ * Note that no_entry_value is the result of {@link #getNoEntryValue()} and represents + * null for this map instance. + * + * @param value double value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( double value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the double value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + double get( Object key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an double value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryValue() + */ + double put( K key, double value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an double value to be associated with the specified key + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + double putIfAbsent( K key, double value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous double value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + double remove( Object key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,double) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TObjectDoubleMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + Object[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + K[] keys( K[] array ); + + + + /** + * Returns a {@link TDoubleCollection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the TDoubleIterator.remove, + * TDoubleCollection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of double values. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of double values. + */ + double[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of double values. + */ + double[] values( double[] array ); + + + /** + * Returns a TObjectDoubleIterator with access to this map's keys and values. + * + * @return a TObjectDoubleIterator with access to this map's keys and values. + */ + public TObjectDoubleIterator iterator(); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( K key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( K key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( K key, double adjust_amount, double put_amount ); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TObjectDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TObjectDoubleProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TObjectFloatMap.java b/src/gnu/trove/map/TObjectFloatMap.java new file mode 100644 index 0000000..918e5f1 --- /dev/null +++ b/src/gnu/trove/map/TObjectFloatMap.java @@ -0,0 +1,460 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.TFloatCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TObjectFloatProcedure; +import gnu.trove.iterator.TObjectFloatIterator; + +import java.util.Map; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of Object keys and float values. + */ +public interface TObjectFloatMap { + + // Query Operations + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + float getNoEntryValue(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( Object key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==no_entry_value ? v==no_entry_value : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + *

+ * Note that no_entry_value is the result of {@link #getNoEntryValue()} and represents + * null for this map instance. + * + * @param value float value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( float value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the float value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + float get( Object key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an float value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryValue() + */ + float put( K key, float value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an float value to be associated with the specified key + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + float putIfAbsent( K key, float value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous float value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + float remove( Object key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,float) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TObjectFloatMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + Object[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + K[] keys( K[] array ); + + + + /** + * Returns a {@link TFloatCollection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the TFloatIterator.remove, + * TFloatCollection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of float values. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of float values. + */ + float[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of float values. + */ + float[] values( float[] array ); + + + /** + * Returns a TObjectFloatIterator with access to this map's keys and values. + * + * @return a TObjectFloatIterator with access to this map's keys and values. + */ + public TObjectFloatIterator iterator(); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( K key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( K key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( K key, float adjust_amount, float put_amount ); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TObjectFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TObjectFloatProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TObjectIntMap.java b/src/gnu/trove/map/TObjectIntMap.java new file mode 100644 index 0000000..fa093f3 --- /dev/null +++ b/src/gnu/trove/map/TObjectIntMap.java @@ -0,0 +1,460 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.TIntCollection; +import gnu.trove.function.TIntFunction; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TObjectIntProcedure; +import gnu.trove.iterator.TObjectIntIterator; + +import java.util.Map; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of Object keys and int values. + */ +public interface TObjectIntMap { + + // Query Operations + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + int getNoEntryValue(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( Object key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==no_entry_value ? v==no_entry_value : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + *

+ * Note that no_entry_value is the result of {@link #getNoEntryValue()} and represents + * null for this map instance. + * + * @param value int value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( int value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the int value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + int get( Object key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an int value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryValue() + */ + int put( K key, int value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an int value to be associated with the specified key + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + int putIfAbsent( K key, int value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous int value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + int remove( Object key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,int) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TObjectIntMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + Object[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + K[] keys( K[] array ); + + + + /** + * Returns a {@link TIntCollection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the TIntIterator.remove, + * TIntCollection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of int values. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of int values. + */ + int[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of int values. + */ + int[] values( int[] array ); + + + /** + * Returns a TObjectIntIterator with access to this map's keys and values. + * + * @return a TObjectIntIterator with access to this map's keys and values. + */ + public TObjectIntIterator iterator(); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( K key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( K key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( K key, int adjust_amount, int put_amount ); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TObjectIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TObjectIntProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TObjectLongMap.java b/src/gnu/trove/map/TObjectLongMap.java new file mode 100644 index 0000000..f588e28 --- /dev/null +++ b/src/gnu/trove/map/TObjectLongMap.java @@ -0,0 +1,460 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.TLongCollection; +import gnu.trove.function.TLongFunction; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.procedure.TObjectLongProcedure; +import gnu.trove.iterator.TObjectLongIterator; + +import java.util.Map; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of Object keys and long values. + */ +public interface TObjectLongMap { + + // Query Operations + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + long getNoEntryValue(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( Object key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==no_entry_value ? v==no_entry_value : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + *

+ * Note that no_entry_value is the result of {@link #getNoEntryValue()} and represents + * null for this map instance. + * + * @param value long value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( long value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the long value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + long get( Object key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an long value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryValue() + */ + long put( K key, long value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an long value to be associated with the specified key + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + long putIfAbsent( K key, long value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous long value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + long remove( Object key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,long) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TObjectLongMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + Object[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + K[] keys( K[] array ); + + + + /** + * Returns a {@link TLongCollection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the TLongIterator.remove, + * TLongCollection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of long values. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of long values. + */ + long[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of long values. + */ + long[] values( long[] array ); + + + /** + * Returns a TObjectLongIterator with access to this map's keys and values. + * + * @return a TObjectLongIterator with access to this map's keys and values. + */ + public TObjectLongIterator iterator(); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( K key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( K key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( K key, long adjust_amount, long put_amount ); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TObjectLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TObjectLongProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TObjectShortMap.java b/src/gnu/trove/map/TObjectShortMap.java new file mode 100644 index 0000000..b0e12b2 --- /dev/null +++ b/src/gnu/trove/map/TObjectShortMap.java @@ -0,0 +1,460 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.TShortCollection; +import gnu.trove.function.TShortFunction; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.procedure.TObjectShortProcedure; +import gnu.trove.iterator.TObjectShortIterator; + +import java.util.Map; +import java.util.Set; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of Object keys and short values. + */ +public interface TObjectShortMap { + + // Query Operations + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + short getNoEntryValue(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * (key==null ? k==null : key.equals(k)). (There can be + * at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( Object key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==no_entry_value ? v==no_entry_value : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + *

+ * Note that no_entry_value is the result of {@link #getNoEntryValue()} and represents + * null for this map instance. + * + * @param value short value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( short value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the short value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + short get( Object key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an short value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryValue() + */ + short put( K key, short value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an short value to be associated with the specified key + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + short putIfAbsent( K key, short value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous short value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + short remove( Object key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,short) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TObjectShortMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link Set} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + Set keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + Object[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + K[] keys( K[] array ); + + + + /** + * Returns a {@link TShortCollection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the TShortIterator.remove, + * TShortCollection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of short values. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of short values. + */ + short[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of short values. + */ + short[] values( short[] array ); + + + /** + * Returns a TObjectShortIterator with access to this map's keys and values. + * + * @return a TObjectShortIterator with access to this map's keys and values. + */ + public TObjectShortIterator iterator(); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( K key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( K key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( K key, short adjust_amount, short put_amount ); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TObjectShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TObjectShortProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TShortByteMap.java b/src/gnu/trove/map/TShortByteMap.java new file mode 100644 index 0000000..dcf19d2 --- /dev/null +++ b/src/gnu/trove/map/TShortByteMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TByteFunction; +import gnu.trove.iterator.TShortByteIterator; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TShortByteProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + + +/** + * Interface for a primitive map of short keys and byte values. + */ +public interface TShortByteMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public short getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public byte getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an short value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte put( short key, byte value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an short value + * @param value an byte value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte putIfAbsent( short key, byte value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TShortByteMap map ); + + + /** + * Retrieves the value for key + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte get( short key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public byte remove( short key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TShortSet + * + * @return the keys of the map as a TShortSet + */ + public TShortSet keySet(); + + + /** + * Returns the keys of the map as an array of short values. + * + * @return the keys of the map as an array of short values. + */ + public short[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public short[] keys( short[] array ); + + + /** + * Returns the values of the map as a TByteCollection + * + * @return the values of the map as a TByteCollection + */ + public TByteCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public byte[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public byte[] values( byte[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an byte value + * @return a boolean value + */ + public boolean containsValue( byte val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an short value + * @return a boolean value + */ + public boolean containsKey( short key ); + + + /** + * @return a TShortByteIterator with access to this map's keys and values + */ + public TShortByteIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOShortByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortByteProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortByteProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( short key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( short key, byte amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public byte adjustOrPutValue( short key, byte adjust_amount, byte put_amount ); +} diff --git a/src/gnu/trove/map/TShortCharMap.java b/src/gnu/trove/map/TShortCharMap.java new file mode 100644 index 0000000..8f7ce00 --- /dev/null +++ b/src/gnu/trove/map/TShortCharMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TCharFunction; +import gnu.trove.iterator.TShortCharIterator; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TShortCharProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + + +/** + * Interface for a primitive map of short keys and char values. + */ +public interface TShortCharMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public short getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public char getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an short value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char put( short key, char value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an short value + * @param value an char value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char putIfAbsent( short key, char value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TShortCharMap map ); + + + /** + * Retrieves the value for key + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char get( short key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public char remove( short key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TShortSet + * + * @return the keys of the map as a TShortSet + */ + public TShortSet keySet(); + + + /** + * Returns the keys of the map as an array of short values. + * + * @return the keys of the map as an array of short values. + */ + public short[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public short[] keys( short[] array ); + + + /** + * Returns the values of the map as a TCharCollection + * + * @return the values of the map as a TCharCollection + */ + public TCharCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public char[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public char[] values( char[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an char value + * @return a boolean value + */ + public boolean containsValue( char val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an short value + * @return a boolean value + */ + public boolean containsKey( short key ); + + + /** + * @return a TShortCharIterator with access to this map's keys and values + */ + public TShortCharIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOShortCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortCharProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortCharProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( short key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( short key, char amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public char adjustOrPutValue( short key, char adjust_amount, char put_amount ); +} diff --git a/src/gnu/trove/map/TShortDoubleMap.java b/src/gnu/trove/map/TShortDoubleMap.java new file mode 100644 index 0000000..5ff6bbd --- /dev/null +++ b/src/gnu/trove/map/TShortDoubleMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TDoubleFunction; +import gnu.trove.iterator.TShortDoubleIterator; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TShortDoubleProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + + +/** + * Interface for a primitive map of short keys and double values. + */ +public interface TShortDoubleMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public short getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public double getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an short value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double put( short key, double value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an short value + * @param value an double value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double putIfAbsent( short key, double value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TShortDoubleMap map ); + + + /** + * Retrieves the value for key + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double get( short key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public double remove( short key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TShortSet + * + * @return the keys of the map as a TShortSet + */ + public TShortSet keySet(); + + + /** + * Returns the keys of the map as an array of short values. + * + * @return the keys of the map as an array of short values. + */ + public short[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public short[] keys( short[] array ); + + + /** + * Returns the values of the map as a TDoubleCollection + * + * @return the values of the map as a TDoubleCollection + */ + public TDoubleCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public double[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public double[] values( double[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an double value + * @return a boolean value + */ + public boolean containsValue( double val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an short value + * @return a boolean value + */ + public boolean containsKey( short key ); + + + /** + * @return a TShortDoubleIterator with access to this map's keys and values + */ + public TShortDoubleIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOShortDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortDoubleProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortDoubleProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( short key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( short key, double amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public double adjustOrPutValue( short key, double adjust_amount, double put_amount ); +} diff --git a/src/gnu/trove/map/TShortFloatMap.java b/src/gnu/trove/map/TShortFloatMap.java new file mode 100644 index 0000000..b318ec2 --- /dev/null +++ b/src/gnu/trove/map/TShortFloatMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TFloatFunction; +import gnu.trove.iterator.TShortFloatIterator; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TShortFloatProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + + +/** + * Interface for a primitive map of short keys and float values. + */ +public interface TShortFloatMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public short getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public float getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an short value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float put( short key, float value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an short value + * @param value an float value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float putIfAbsent( short key, float value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TShortFloatMap map ); + + + /** + * Retrieves the value for key + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float get( short key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public float remove( short key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TShortSet + * + * @return the keys of the map as a TShortSet + */ + public TShortSet keySet(); + + + /** + * Returns the keys of the map as an array of short values. + * + * @return the keys of the map as an array of short values. + */ + public short[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public short[] keys( short[] array ); + + + /** + * Returns the values of the map as a TFloatCollection + * + * @return the values of the map as a TFloatCollection + */ + public TFloatCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public float[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public float[] values( float[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an float value + * @return a boolean value + */ + public boolean containsValue( float val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an short value + * @return a boolean value + */ + public boolean containsKey( short key ); + + + /** + * @return a TShortFloatIterator with access to this map's keys and values + */ + public TShortFloatIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOShortFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortFloatProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortFloatProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( short key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( short key, float amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public float adjustOrPutValue( short key, float adjust_amount, float put_amount ); +} diff --git a/src/gnu/trove/map/TShortIntMap.java b/src/gnu/trove/map/TShortIntMap.java new file mode 100644 index 0000000..356e816 --- /dev/null +++ b/src/gnu/trove/map/TShortIntMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TIntFunction; +import gnu.trove.iterator.TShortIntIterator; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TShortIntProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + + +/** + * Interface for a primitive map of short keys and int values. + */ +public interface TShortIntMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public short getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public int getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an short value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int put( short key, int value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an short value + * @param value an int value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int putIfAbsent( short key, int value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TShortIntMap map ); + + + /** + * Retrieves the value for key + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int get( short key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public int remove( short key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TShortSet + * + * @return the keys of the map as a TShortSet + */ + public TShortSet keySet(); + + + /** + * Returns the keys of the map as an array of short values. + * + * @return the keys of the map as an array of short values. + */ + public short[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public short[] keys( short[] array ); + + + /** + * Returns the values of the map as a TIntCollection + * + * @return the values of the map as a TIntCollection + */ + public TIntCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public int[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public int[] values( int[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an int value + * @return a boolean value + */ + public boolean containsValue( int val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an short value + * @return a boolean value + */ + public boolean containsKey( short key ); + + + /** + * @return a TShortIntIterator with access to this map's keys and values + */ + public TShortIntIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOShortIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortIntProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortIntProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( short key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( short key, int amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public int adjustOrPutValue( short key, int adjust_amount, int put_amount ); +} diff --git a/src/gnu/trove/map/TShortLongMap.java b/src/gnu/trove/map/TShortLongMap.java new file mode 100644 index 0000000..ff13106 --- /dev/null +++ b/src/gnu/trove/map/TShortLongMap.java @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TLongCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TLongFunction; +import gnu.trove.iterator.TShortLongIterator; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.procedure.TShortLongProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + + +/** + * Interface for a primitive map of short keys and long values. + */ +public interface TShortLongMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public short getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public long getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an short value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long put( short key, long value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an short value + * @param value an long value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long putIfAbsent( short key, long value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TShortLongMap map ); + + + /** + * Retrieves the value for key + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long get( short key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public long remove( short key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TShortSet + * + * @return the keys of the map as a TShortSet + */ + public TShortSet keySet(); + + + /** + * Returns the keys of the map as an array of short values. + * + * @return the keys of the map as an array of short values. + */ + public short[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public short[] keys( short[] array ); + + + /** + * Returns the values of the map as a TLongCollection + * + * @return the values of the map as a TLongCollection + */ + public TLongCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public long[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public long[] values( long[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an long value + * @return a boolean value + */ + public boolean containsValue( long val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an short value + * @return a boolean value + */ + public boolean containsKey( short key ); + + + /** + * @return a TShortLongIterator with access to this map's keys and values + */ + public TShortLongIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOShortLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortLongProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortLongProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( short key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( short key, long amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public long adjustOrPutValue( short key, long adjust_amount, long put_amount ); +} diff --git a/src/gnu/trove/map/TShortObjectMap.java b/src/gnu/trove/map/TShortObjectMap.java new file mode 100644 index 0000000..30d54f3 --- /dev/null +++ b/src/gnu/trove/map/TShortObjectMap.java @@ -0,0 +1,427 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + +import gnu.trove.iterator.TShortObjectIterator; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TShortObjectProcedure; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TShortSet; + +import java.util.Collection; +import java.util.Map; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for a primitive map of short keys and Object values. + */ +public interface TShortObjectMap { + +// Query Operations + + /** + * Returns the value that represents null in the {@link #keySet()}. + * The default value is generally zero, but can be changed during + * construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + short getNoEntryKey(); + + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of key-value mappings in this map + */ + int size(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + boolean isEmpty(); + + + /** + * Returns true if this map contains a mapping for the specified + * key. More formally, returns true if and only if + * this map contains a mapping for a key k such that + * key.equals(k). (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified + * key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey( short key ); + + + /** + * Returns true if this map maps one or more keys to the + * specified value. More formally, returns true if and only if + * this map contains at least one mapping to a value v such that + * (value==null ? v==null : value.equals(v)). This operation + * will probably require time linear in the map size for most + * implementations of the Map interface. + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the + * specified value + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified value is null and this + * map does not permit null values (optional) + */ + boolean containsValue( Object value ); + + + /** + * 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==null ? k==null : + * key.equals(k))}, then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + *

If this map permits null values, then 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. + * + * @param key the key whose associated value is to be returned + * @return the short value to which the specified key is mapped, or + * {@code null} if this map contains no mapping for the key + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + V get( short key ); + + + // Modification Operations + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only + * if {@link #containsKey(short) m.containsKey(k)} would return + * true.) + * + * @param key key with which the specified value is to be associated + * @param value an short value value to be associated with the specified key + * @return the previous value associated with key, or + * no_entry_value if there was no mapping for key. + * (A no_entry_value return can also indicate that the map + * previously associated null with key, + * if the implementation supports null values.) + * @throws UnsupportedOperationException if the put operation + * is not supported by this map + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map + * @throws NullPointerException if the specified key or value is null + * and this map does not permit null keys or values + * @throws IllegalArgumentException if some property of the specified key + * or value prevents it from being stored in this map + * @see #getNoEntryKey() + */ + V put( short key, V value); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key key with which the specified value is to be associated + * @param value an short value to be associated with the specified key + * + * @return the previous value associated with key, or null + * if none was found. + */ + V putIfAbsent( short key, V value ); + + + /** + * Removes the mapping for a key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key k to value v such that + * key.equals(k), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

Returns the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + * + *

If this map permits null values, then a return value of + * null does not necessarily indicate that the map + * contained no mapping for the key; it's also possible that the map + * explicitly mapped the key to null. + * + *

The map will not contain a mapping for the specified key once the + * call returns. + * + * @param key key whose mapping is to be removed from the map + * @return the previous short value associated with key, or + * null if there was no mapping for key. + * @throws UnsupportedOperationException if the remove operation + * is not supported by this map + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional) + * @throws NullPointerException if the specified key is null and this + * map does not permit null keys (optional) + */ + V remove( short key ); + + + // Bulk Operations + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(short,Object) put(k, v)} on this map once + * for each mapping from key k to value v in the + * specified map. The behavior of this operation is undefined if the + * specified map is modified while the operation is in progress. + * + * @param m mappings to be stored in this map + * @throws UnsupportedOperationException if the putAll operation + * is not supported by 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 if + * this map does not permit null keys or values, and the + * specified map contains null keys or values + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + void putAll( Map m); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + void putAll( TShortObjectMap map ); + + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the clear operation + * is not supported by this map + */ + void clear(); + + + // Views + + /** + * Returns a {@link TShortSet} view of the keys contained in this map. + * 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 remove operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear + * operations. It does not support the add or addAll + * operations. + * + * @return a set view of the keys contained in this map + */ + TShortSet keySet(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @return a copy of the keys of the map as an array. + */ + short[] keys(); + + + /** + * Returns a copy of the keys of the map as an array. + * Changes to the array of keys will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + short[] keys( short[] array ); + + + + /** + * Returns a {@link Collection} view of the values contained in this map. + * 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 remove operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the Iterator.remove, + * Collection.remove, removeAll, + * retainAll and clear operations. It does not + * support the add or addAll operations. + * + * @return a collection view of the values contained in this map + */ + Collection valueCollection(); + + + /** + * Returns the values of the map as an Object array. Note that the array returned + * is typed as an Object[] and may not be cast to a more specific type. See + * {@link #values(V[])} for a version which allows specifically typed arrays. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @return the values of the map as an array of short values. + */ + Object[] values(); + + + /** + * Returns the values of the map using an existing array. + * Changes to the array of values will not be reflected in the map + * nor vice-versa. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of short values. + */ + V[] values( V[] array ); + + + /** + * Returns a TShortObjectIterator with access to this map's keys and values. + * + * @return a TShortObjectIterator with access to this map's keys and values. + */ + public TShortObjectIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TShortObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortObjectProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortObjectProcedure procedure ); + + + // 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. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + boolean equals( Object o ); + + + /** + * 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}. + * + * @return the hash code value for this map + + * @see Object#equals(Object) + * @see #equals(Object) + */ + int hashCode(); +} diff --git a/src/gnu/trove/map/TShortShortMap.java b/src/gnu/trove/map/TShortShortMap.java new file mode 100644 index 0000000..1f4a8fb --- /dev/null +++ b/src/gnu/trove/map/TShortShortMap.java @@ -0,0 +1,302 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map; + + +import java.util.Map; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// +import gnu.trove.function.TShortFunction; +import gnu.trove.iterator.TShortShortIterator; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.procedure.TShortShortProcedure; +import gnu.trove.set.TShortSet; + + +/** + * Interface for a primitive map of short keys and short values. + */ +public interface TShortShortMap { + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null key in this collection. + */ + public short getNoEntryKey(); + + + /** + * Returns the value that will be returned from {@link #get} or {@link #put} if no + * entry exists for a given key. The default value is generally zero, but can be + * changed during construction of the collection. + * + * @return the value that represents a null value in this collection. + */ + public short getNoEntryValue(); + + + /** + * Inserts a key/value pair into the map. + * + * @param key an short value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short put( short key, short value ); + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an short value + * @param value an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short putIfAbsent( short key, short value ); + + + /** + * Put all the entries from the given Map into this map. + * + * @param map The Map from which entries will be obtained to put into this map. + */ + public void putAll( Map map ); + + + /** + * Put all the entries from the given map into this map. + * + * @param map The map from which entries will be obtained to put into this map. + */ + public void putAll( TShortShortMap map ); + + + /** + * Retrieves the value for key + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short get( short key ); + + + /** + * Empties the map. + */ + public void clear(); + + + /** + * Returns true if this map contains no key-value mappings. + * + * @return true if this map contains no key-value mappings + */ + public boolean isEmpty(); + + + /** + * Deletes a key/value pair from the map. + * + * @param key an short value + * + * @return the previous value associated with key, or the "no entry" value + * if none was found (see {@link #getNoEntryValue}). + */ + public short remove( short key ); + + + /** + * Returns an int value that is the number of elements in the map. + * + * @return an int value that is the number of elements in the map. + */ + public int size(); + + + /** + * Returns the keys of the map as a TShortSet + * + * @return the keys of the map as a TShortSet + */ + public TShortSet keySet(); + + + /** + * Returns the keys of the map as an array of short values. + * + * @return the keys of the map as an array of short values. + */ + public short[] keys(); + + + /** + * Returns the keys of the map. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the keys of the map as an array. + */ + public short[] keys( short[] array ); + + + /** + * Returns the values of the map as a TShortCollection + * + * @return the values of the map as a TShortCollection + */ + public TShortCollection valueCollection(); + + + /** + * Returns the values of the map as an array of #e# values. + * + * @return the values of the map as an array of #e# values. + */ + public short[] values(); + + + /** + * Returns the values of the map using an existing array. + * + * @param array the array into which the elements of the list are to be stored, + * if it is big enough; otherwise, a new array of the same type is + * allocated for this purpose. + * @return the values of the map as an array of #e# values. + */ + public short[] values( short[] array ); + + + /** + * Checks for the presence of val in the values of the map. + * + * @param val an short value + * @return a boolean value + */ + public boolean containsValue( short val ); + + + /** + * Checks for the present of key in the keys of the map. + * + * @param key an short value + * @return a boolean value + */ + public boolean containsKey( short key ); + + + /** + * @return a TShortShortIterator with access to this map's keys and values + */ + public TShortShortIterator iterator(); + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TShortProcedure procedure ); + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a T#F#Procedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ); + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOShortShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + public boolean forEachEntry( TShortShortProcedure procedure ); + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ); + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + public boolean retainEntries( TShortShortProcedure procedure ); + + + /** + * Increments the primitive value mapped to key by 1 + * + * @param key the key of the value to increment + * @return true if a mapping was found and modified. + */ + public boolean increment( short key ); + + + /** + * Adjusts the primitive value mapped to key. + * + * @param key the key of the value to increment + * @param amount the amount to adjust the value by. + * @return true if a mapping was found and modified. + */ + public boolean adjustValue( short key, short amount ); + + + /** + * Adjusts the primitive value mapped to the key if the key is present in the map. + * Otherwise, the initial_value is put in the map. + * + * @param key the key of the value to increment + * @param adjust_amount the amount to adjust the value by + * @param put_amount the value put into the map if the key is not initial present + * + * @return the value present in the map after the adjustment or put operation + */ + public short adjustOrPutValue( short key, short adjust_amount, short put_amount ); +} diff --git a/src/gnu/trove/map/custom_hash/TObjectByteCustomHashMap.java b/src/gnu/trove/map/custom_hash/TObjectByteCustomHashMap.java new file mode 100644 index 0000000..3c24d7c --- /dev/null +++ b/src/gnu/trove/map/custom_hash/TObjectByteCustomHashMap.java @@ -0,0 +1,1171 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.custom_hash; + +import gnu.trove.TByteCollection; +import gnu.trove.function.TByteFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.impl.hash.THash; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TObjectByteIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TObjectByteMap; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TObjectByteProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.*; +import java.util.*; + + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and byte values. + * + * @author Rob Eden + */ +public class TObjectByteCustomHashMap extends TCustomObjectHash + implements TObjectByteMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectByteProcedure PUT_ALL_PROC = new TObjectByteProcedure() { + public boolean execute(K key, byte value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient byte[] _values; + + /** the value that represents null */ + protected byte no_entry_value; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TObjectByteCustomHashMap() {} + + + /** + * Creates a new TObjectByteHashMap instance with the default + * capacity and load factor. + */ + public TObjectByteCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectByteCustomHashMap( HashingStrategy strategy, + int initialCapacity ) { + + super( strategy, initialCapacity ); + + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectByteCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectByteHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectByteCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor, byte noEntryValue ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectByteCustomHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectByteMap to be copied. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TObjectByteCustomHashMap( HashingStrategy strategy, + TObjectByteMap map ) { + + this( strategy, map.size(), 0.5f, map.getNoEntryValue() ); + + if ( map instanceof TObjectByteCustomHashMap ) { + TObjectByteCustomHashMap hashmap = ( TObjectByteCustomHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + this.strategy = hashmap.strategy; + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + byte oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new byte[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + K o = oldKeys[i]; + if( o != FREE && o != REMOVED ) { + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + Object[] keys = _set; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public byte get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public byte put( K key, byte value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( K key, byte value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private byte doPut( byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public byte remove( Object key ) { + byte prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectByteMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TByteValueCollection(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + byte[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectByteIterator iterator() { + return new TObjectByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (byte)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, byte amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( final K key, final byte adjust_amount, + final byte put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ) { + Object[] keys = _set; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectByteProcedure procedure ) { + Object[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectByteProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + byte[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ) { + Object[] keys = _set; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectByteMap ) ) { + return false; + } + TObjectByteMap that = ( TObjectByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectByteIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + byte value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectByteCustomHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectByteCustomHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectByteCustomHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectByteCustomHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectByteCustomHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectByteCustomHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TByteValueCollection implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TObjectByteValueHashIterator(); + } + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TObjectByteCustomHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public byte[] toArray() { + return TObjectByteCustomHashMap.this.values(); + } + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TObjectByteCustomHashMap.this.values( dest ); + } + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TObjectByteCustomHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectByteCustomHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TObjectByteCustomHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectByteCustomHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TObjectByteCustomHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectByteValueHashIterator implements TByteIterator { + + protected THash _hash = TObjectByteCustomHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectByteValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectByteCustomHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectByteCustomHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TCustomObjectHash.FREE || + set[i] == TCustomObjectHash.REMOVED ) ) { + ; + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectByteHashIterator extends TObjectHashIterator + implements TObjectByteIterator { + + /** the collection being iterated over */ + private final TObjectByteCustomHashMap _map; + + public TObjectByteHashIterator( TObjectByteCustomHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + strategy = ( HashingStrategy ) in.readObject(); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + byte val = in.readByte(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectByteProcedure() { + private boolean first = true; + public boolean execute( K key, byte value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} diff --git a/src/gnu/trove/map/custom_hash/TObjectCharCustomHashMap.java b/src/gnu/trove/map/custom_hash/TObjectCharCustomHashMap.java new file mode 100644 index 0000000..e346dcb --- /dev/null +++ b/src/gnu/trove/map/custom_hash/TObjectCharCustomHashMap.java @@ -0,0 +1,1171 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.custom_hash; + +import gnu.trove.TCharCollection; +import gnu.trove.function.TCharFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.impl.hash.THash; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TObjectCharIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TObjectCharMap; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TObjectCharProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.*; +import java.util.*; + + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and char values. + * + * @author Rob Eden + */ +public class TObjectCharCustomHashMap extends TCustomObjectHash + implements TObjectCharMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectCharProcedure PUT_ALL_PROC = new TObjectCharProcedure() { + public boolean execute(K key, char value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient char[] _values; + + /** the value that represents null */ + protected char no_entry_value; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TObjectCharCustomHashMap() {} + + + /** + * Creates a new TObjectCharHashMap instance with the default + * capacity and load factor. + */ + public TObjectCharCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectCharCustomHashMap( HashingStrategy strategy, + int initialCapacity ) { + + super( strategy, initialCapacity ); + + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectCharCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectCharHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectCharCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor, char noEntryValue ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectCharCustomHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectCharMap to be copied. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TObjectCharCustomHashMap( HashingStrategy strategy, + TObjectCharMap map ) { + + this( strategy, map.size(), 0.5f, map.getNoEntryValue() ); + + if ( map instanceof TObjectCharCustomHashMap ) { + TObjectCharCustomHashMap hashmap = ( TObjectCharCustomHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + this.strategy = hashmap.strategy; + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + char oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new char[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + K o = oldKeys[i]; + if( o != FREE && o != REMOVED ) { + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + Object[] keys = _set; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public char get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public char put( K key, char value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( K key, char value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private char doPut( char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public char remove( Object key ) { + char prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectCharMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TCharValueCollection(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + char[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectCharIterator iterator() { + return new TObjectCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (char)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, char amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( final K key, final char adjust_amount, + final char put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ) { + Object[] keys = _set; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectCharProcedure procedure ) { + Object[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectCharProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + char[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ) { + Object[] keys = _set; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectCharMap ) ) { + return false; + } + TObjectCharMap that = ( TObjectCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectCharIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + char value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectCharCustomHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectCharCustomHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectCharCustomHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectCharCustomHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectCharCustomHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectCharCustomHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TCharValueCollection implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TObjectCharValueHashIterator(); + } + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TObjectCharCustomHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public char[] toArray() { + return TObjectCharCustomHashMap.this.values(); + } + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TObjectCharCustomHashMap.this.values( dest ); + } + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TObjectCharCustomHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectCharCustomHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TObjectCharCustomHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectCharCustomHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TObjectCharCustomHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectCharValueHashIterator implements TCharIterator { + + protected THash _hash = TObjectCharCustomHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectCharValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectCharCustomHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectCharCustomHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TCustomObjectHash.FREE || + set[i] == TCustomObjectHash.REMOVED ) ) { + ; + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectCharHashIterator extends TObjectHashIterator + implements TObjectCharIterator { + + /** the collection being iterated over */ + private final TObjectCharCustomHashMap _map; + + public TObjectCharHashIterator( TObjectCharCustomHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + strategy = ( HashingStrategy ) in.readObject(); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + char val = in.readChar(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectCharProcedure() { + private boolean first = true; + public boolean execute( K key, char value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} diff --git a/src/gnu/trove/map/custom_hash/TObjectDoubleCustomHashMap.java b/src/gnu/trove/map/custom_hash/TObjectDoubleCustomHashMap.java new file mode 100644 index 0000000..51b204f --- /dev/null +++ b/src/gnu/trove/map/custom_hash/TObjectDoubleCustomHashMap.java @@ -0,0 +1,1171 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.custom_hash; + +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.impl.hash.THash; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TObjectDoubleIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TObjectDoubleMap; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TObjectDoubleProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.*; +import java.util.*; + + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and double values. + * + * @author Rob Eden + */ +public class TObjectDoubleCustomHashMap extends TCustomObjectHash + implements TObjectDoubleMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectDoubleProcedure PUT_ALL_PROC = new TObjectDoubleProcedure() { + public boolean execute(K key, double value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient double[] _values; + + /** the value that represents null */ + protected double no_entry_value; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TObjectDoubleCustomHashMap() {} + + + /** + * Creates a new TObjectDoubleHashMap instance with the default + * capacity and load factor. + */ + public TObjectDoubleCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectDoubleCustomHashMap( HashingStrategy strategy, + int initialCapacity ) { + + super( strategy, initialCapacity ); + + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectDoubleCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectDoubleHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectDoubleCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor, double noEntryValue ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectDoubleCustomHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectDoubleMap to be copied. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TObjectDoubleCustomHashMap( HashingStrategy strategy, + TObjectDoubleMap map ) { + + this( strategy, map.size(), 0.5f, map.getNoEntryValue() ); + + if ( map instanceof TObjectDoubleCustomHashMap ) { + TObjectDoubleCustomHashMap hashmap = ( TObjectDoubleCustomHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + this.strategy = hashmap.strategy; + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + double oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new double[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + K o = oldKeys[i]; + if( o != FREE && o != REMOVED ) { + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + Object[] keys = _set; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public double get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public double put( K key, double value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( K key, double value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private double doPut( double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public double remove( Object key ) { + double prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectDoubleMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TDoubleValueCollection(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + double[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectDoubleIterator iterator() { + return new TObjectDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (double)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, double amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( final K key, final double adjust_amount, + final double put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ) { + Object[] keys = _set; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectDoubleProcedure procedure ) { + Object[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectDoubleProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + double[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ) { + Object[] keys = _set; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectDoubleMap ) ) { + return false; + } + TObjectDoubleMap that = ( TObjectDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectDoubleIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + double value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectDoubleCustomHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectDoubleCustomHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectDoubleCustomHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectDoubleCustomHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectDoubleCustomHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectDoubleCustomHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TDoubleValueCollection implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TObjectDoubleValueHashIterator(); + } + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TObjectDoubleCustomHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public double[] toArray() { + return TObjectDoubleCustomHashMap.this.values(); + } + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TObjectDoubleCustomHashMap.this.values( dest ); + } + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TObjectDoubleCustomHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectDoubleCustomHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TObjectDoubleCustomHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectDoubleCustomHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TObjectDoubleCustomHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectDoubleValueHashIterator implements TDoubleIterator { + + protected THash _hash = TObjectDoubleCustomHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectDoubleValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectDoubleCustomHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectDoubleCustomHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TCustomObjectHash.FREE || + set[i] == TCustomObjectHash.REMOVED ) ) { + ; + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectDoubleHashIterator extends TObjectHashIterator + implements TObjectDoubleIterator { + + /** the collection being iterated over */ + private final TObjectDoubleCustomHashMap _map; + + public TObjectDoubleHashIterator( TObjectDoubleCustomHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + strategy = ( HashingStrategy ) in.readObject(); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + double val = in.readDouble(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectDoubleProcedure() { + private boolean first = true; + public boolean execute( K key, double value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} diff --git a/src/gnu/trove/map/custom_hash/TObjectFloatCustomHashMap.java b/src/gnu/trove/map/custom_hash/TObjectFloatCustomHashMap.java new file mode 100644 index 0000000..dcf6907 --- /dev/null +++ b/src/gnu/trove/map/custom_hash/TObjectFloatCustomHashMap.java @@ -0,0 +1,1171 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.custom_hash; + +import gnu.trove.TFloatCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.impl.hash.THash; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TObjectFloatIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TObjectFloatMap; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TObjectFloatProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.*; +import java.util.*; + + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and float values. + * + * @author Rob Eden + */ +public class TObjectFloatCustomHashMap extends TCustomObjectHash + implements TObjectFloatMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectFloatProcedure PUT_ALL_PROC = new TObjectFloatProcedure() { + public boolean execute(K key, float value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient float[] _values; + + /** the value that represents null */ + protected float no_entry_value; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TObjectFloatCustomHashMap() {} + + + /** + * Creates a new TObjectFloatHashMap instance with the default + * capacity and load factor. + */ + public TObjectFloatCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectFloatCustomHashMap( HashingStrategy strategy, + int initialCapacity ) { + + super( strategy, initialCapacity ); + + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectFloatCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectFloatHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectFloatCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor, float noEntryValue ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectFloatCustomHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectFloatMap to be copied. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TObjectFloatCustomHashMap( HashingStrategy strategy, + TObjectFloatMap map ) { + + this( strategy, map.size(), 0.5f, map.getNoEntryValue() ); + + if ( map instanceof TObjectFloatCustomHashMap ) { + TObjectFloatCustomHashMap hashmap = ( TObjectFloatCustomHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + this.strategy = hashmap.strategy; + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + float oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new float[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + K o = oldKeys[i]; + if( o != FREE && o != REMOVED ) { + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + Object[] keys = _set; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public float get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public float put( K key, float value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( K key, float value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private float doPut( float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public float remove( Object key ) { + float prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectFloatMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TFloatValueCollection(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + float[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectFloatIterator iterator() { + return new TObjectFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (float)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, float amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( final K key, final float adjust_amount, + final float put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ) { + Object[] keys = _set; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectFloatProcedure procedure ) { + Object[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectFloatProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + float[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ) { + Object[] keys = _set; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectFloatMap ) ) { + return false; + } + TObjectFloatMap that = ( TObjectFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectFloatIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + float value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectFloatCustomHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectFloatCustomHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectFloatCustomHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectFloatCustomHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectFloatCustomHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectFloatCustomHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TFloatValueCollection implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TObjectFloatValueHashIterator(); + } + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TObjectFloatCustomHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public float[] toArray() { + return TObjectFloatCustomHashMap.this.values(); + } + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TObjectFloatCustomHashMap.this.values( dest ); + } + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TObjectFloatCustomHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectFloatCustomHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TObjectFloatCustomHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectFloatCustomHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TObjectFloatCustomHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectFloatValueHashIterator implements TFloatIterator { + + protected THash _hash = TObjectFloatCustomHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectFloatValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectFloatCustomHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectFloatCustomHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TCustomObjectHash.FREE || + set[i] == TCustomObjectHash.REMOVED ) ) { + ; + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectFloatHashIterator extends TObjectHashIterator + implements TObjectFloatIterator { + + /** the collection being iterated over */ + private final TObjectFloatCustomHashMap _map; + + public TObjectFloatHashIterator( TObjectFloatCustomHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + strategy = ( HashingStrategy ) in.readObject(); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + float val = in.readFloat(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectFloatProcedure() { + private boolean first = true; + public boolean execute( K key, float value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} diff --git a/src/gnu/trove/map/custom_hash/TObjectIntCustomHashMap.java b/src/gnu/trove/map/custom_hash/TObjectIntCustomHashMap.java new file mode 100644 index 0000000..e64d373 --- /dev/null +++ b/src/gnu/trove/map/custom_hash/TObjectIntCustomHashMap.java @@ -0,0 +1,1171 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.custom_hash; + +import gnu.trove.TIntCollection; +import gnu.trove.function.TIntFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.impl.hash.THash; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.iterator.TObjectIntIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TObjectIntMap; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TObjectIntProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.*; +import java.util.*; + + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and int values. + * + * @author Rob Eden + */ +public class TObjectIntCustomHashMap extends TCustomObjectHash + implements TObjectIntMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectIntProcedure PUT_ALL_PROC = new TObjectIntProcedure() { + public boolean execute(K key, int value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient int[] _values; + + /** the value that represents null */ + protected int no_entry_value; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TObjectIntCustomHashMap() {} + + + /** + * Creates a new TObjectIntHashMap instance with the default + * capacity and load factor. + */ + public TObjectIntCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectIntCustomHashMap( HashingStrategy strategy, + int initialCapacity ) { + + super( strategy, initialCapacity ); + + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectIntCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectIntHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectIntCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor, int noEntryValue ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectIntCustomHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectIntMap to be copied. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TObjectIntCustomHashMap( HashingStrategy strategy, + TObjectIntMap map ) { + + this( strategy, map.size(), 0.5f, map.getNoEntryValue() ); + + if ( map instanceof TObjectIntCustomHashMap ) { + TObjectIntCustomHashMap hashmap = ( TObjectIntCustomHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + this.strategy = hashmap.strategy; + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + int oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new int[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + K o = oldKeys[i]; + if( o != FREE && o != REMOVED ) { + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + Object[] keys = _set; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public int get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public int put( K key, int value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( K key, int value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private int doPut( int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public int remove( Object key ) { + int prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectIntMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TIntValueCollection(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + int[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectIntIterator iterator() { + return new TObjectIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (int)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, int amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( final K key, final int adjust_amount, + final int put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ) { + Object[] keys = _set; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectIntProcedure procedure ) { + Object[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectIntProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + int[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ) { + Object[] keys = _set; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectIntMap ) ) { + return false; + } + TObjectIntMap that = ( TObjectIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectIntIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + int value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectIntCustomHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectIntCustomHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectIntCustomHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectIntCustomHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectIntCustomHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectIntCustomHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TIntValueCollection implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TObjectIntValueHashIterator(); + } + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TObjectIntCustomHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public int[] toArray() { + return TObjectIntCustomHashMap.this.values(); + } + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TObjectIntCustomHashMap.this.values( dest ); + } + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TObjectIntCustomHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectIntCustomHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TObjectIntCustomHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectIntCustomHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TObjectIntCustomHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectIntValueHashIterator implements TIntIterator { + + protected THash _hash = TObjectIntCustomHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectIntValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectIntCustomHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectIntCustomHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TCustomObjectHash.FREE || + set[i] == TCustomObjectHash.REMOVED ) ) { + ; + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectIntHashIterator extends TObjectHashIterator + implements TObjectIntIterator { + + /** the collection being iterated over */ + private final TObjectIntCustomHashMap _map; + + public TObjectIntHashIterator( TObjectIntCustomHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + strategy = ( HashingStrategy ) in.readObject(); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + int val = in.readInt(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectIntProcedure() { + private boolean first = true; + public boolean execute( K key, int value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} diff --git a/src/gnu/trove/map/custom_hash/TObjectLongCustomHashMap.java b/src/gnu/trove/map/custom_hash/TObjectLongCustomHashMap.java new file mode 100644 index 0000000..18711aa --- /dev/null +++ b/src/gnu/trove/map/custom_hash/TObjectLongCustomHashMap.java @@ -0,0 +1,1171 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.custom_hash; + +import gnu.trove.TLongCollection; +import gnu.trove.function.TLongFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.impl.hash.THash; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.iterator.TObjectLongIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TObjectLongMap; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.procedure.TObjectLongProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.*; +import java.util.*; + + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and long values. + * + * @author Rob Eden + */ +public class TObjectLongCustomHashMap extends TCustomObjectHash + implements TObjectLongMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectLongProcedure PUT_ALL_PROC = new TObjectLongProcedure() { + public boolean execute(K key, long value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient long[] _values; + + /** the value that represents null */ + protected long no_entry_value; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TObjectLongCustomHashMap() {} + + + /** + * Creates a new TObjectLongHashMap instance with the default + * capacity and load factor. + */ + public TObjectLongCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectLongCustomHashMap( HashingStrategy strategy, + int initialCapacity ) { + + super( strategy, initialCapacity ); + + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectLongCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectLongHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectLongCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor, long noEntryValue ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectLongCustomHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectLongMap to be copied. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TObjectLongCustomHashMap( HashingStrategy strategy, + TObjectLongMap map ) { + + this( strategy, map.size(), 0.5f, map.getNoEntryValue() ); + + if ( map instanceof TObjectLongCustomHashMap ) { + TObjectLongCustomHashMap hashmap = ( TObjectLongCustomHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + this.strategy = hashmap.strategy; + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + long oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new long[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + K o = oldKeys[i]; + if( o != FREE && o != REMOVED ) { + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + Object[] keys = _set; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public long get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public long put( K key, long value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( K key, long value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private long doPut( long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public long remove( Object key ) { + long prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectLongMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TLongValueCollection(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + long[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectLongIterator iterator() { + return new TObjectLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (long)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, long amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( final K key, final long adjust_amount, + final long put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ) { + Object[] keys = _set; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectLongProcedure procedure ) { + Object[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectLongProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + long[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ) { + Object[] keys = _set; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectLongMap ) ) { + return false; + } + TObjectLongMap that = ( TObjectLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectLongIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + long value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectLongCustomHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectLongCustomHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectLongCustomHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectLongCustomHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectLongCustomHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectLongCustomHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TLongValueCollection implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TObjectLongValueHashIterator(); + } + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TObjectLongCustomHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public long[] toArray() { + return TObjectLongCustomHashMap.this.values(); + } + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TObjectLongCustomHashMap.this.values( dest ); + } + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TObjectLongCustomHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectLongCustomHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TObjectLongCustomHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectLongCustomHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TObjectLongCustomHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectLongValueHashIterator implements TLongIterator { + + protected THash _hash = TObjectLongCustomHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectLongValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectLongCustomHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectLongCustomHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TCustomObjectHash.FREE || + set[i] == TCustomObjectHash.REMOVED ) ) { + ; + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectLongHashIterator extends TObjectHashIterator + implements TObjectLongIterator { + + /** the collection being iterated over */ + private final TObjectLongCustomHashMap _map; + + public TObjectLongHashIterator( TObjectLongCustomHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + strategy = ( HashingStrategy ) in.readObject(); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + long val = in.readLong(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectLongProcedure() { + private boolean first = true; + public boolean execute( K key, long value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} diff --git a/src/gnu/trove/map/custom_hash/TObjectShortCustomHashMap.java b/src/gnu/trove/map/custom_hash/TObjectShortCustomHashMap.java new file mode 100644 index 0000000..9c7ccc7 --- /dev/null +++ b/src/gnu/trove/map/custom_hash/TObjectShortCustomHashMap.java @@ -0,0 +1,1171 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.custom_hash; + +import gnu.trove.TShortCollection; +import gnu.trove.function.TShortFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.impl.hash.THash; +import gnu.trove.iterator.TShortIterator; +import gnu.trove.iterator.TObjectShortIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TObjectShortMap; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.procedure.TObjectShortProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.*; +import java.util.*; + + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and short values. + * + * @author Rob Eden + */ +public class TObjectShortCustomHashMap extends TCustomObjectHash + implements TObjectShortMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectShortProcedure PUT_ALL_PROC = new TObjectShortProcedure() { + public boolean execute(K key, short value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient short[] _values; + + /** the value that represents null */ + protected short no_entry_value; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TObjectShortCustomHashMap() {} + + + /** + * Creates a new TObjectShortHashMap instance with the default + * capacity and load factor. + */ + public TObjectShortCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectShortCustomHashMap( HashingStrategy strategy, + int initialCapacity ) { + + super( strategy, initialCapacity ); + + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectShortCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectShortHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectShortCustomHashMap( HashingStrategy strategy, + int initialCapacity, float loadFactor, short noEntryValue ) { + + super( strategy, initialCapacity, loadFactor ); + + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectShortCustomHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectShortMap to be copied. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public TObjectShortCustomHashMap( HashingStrategy strategy, + TObjectShortMap map ) { + + this( strategy, map.size(), 0.5f, map.getNoEntryValue() ); + + if ( map instanceof TObjectShortCustomHashMap ) { + TObjectShortCustomHashMap hashmap = ( TObjectShortCustomHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + this.strategy = hashmap.strategy; + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + short oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new short[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + K o = oldKeys[i]; + if( o != FREE && o != REMOVED ) { + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + Object[] keys = _set; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public short get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public short put( K key, short value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( K key, short value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private short doPut( short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public short remove( Object key ) { + short prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectShortMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TShortValueCollection(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + short[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectShortIterator iterator() { + return new TObjectShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (short)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, short amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( final K key, final short adjust_amount, + final short put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ) { + Object[] keys = _set; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectShortProcedure procedure ) { + Object[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectShortProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + short[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ) { + Object[] keys = _set; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectShortMap ) ) { + return false; + } + TObjectShortMap that = ( TObjectShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectShortIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + short value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectShortCustomHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectShortCustomHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectShortCustomHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectShortCustomHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectShortCustomHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectShortCustomHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TShortValueCollection implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TObjectShortValueHashIterator(); + } + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TObjectShortCustomHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public short[] toArray() { + return TObjectShortCustomHashMap.this.values(); + } + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TObjectShortCustomHashMap.this.values( dest ); + } + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TObjectShortCustomHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectShortCustomHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TObjectShortCustomHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectShortCustomHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TObjectShortCustomHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectShortValueHashIterator implements TShortIterator { + + protected THash _hash = TObjectShortCustomHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectShortValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectShortCustomHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws java.util.ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectShortCustomHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TCustomObjectHash.FREE || + set[i] == TCustomObjectHash.REMOVED ) ) { + ; + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectShortHashIterator extends TObjectHashIterator + implements TObjectShortIterator { + + /** the collection being iterated over */ + private final TObjectShortCustomHashMap _map; + + public TObjectShortHashIterator( TObjectShortCustomHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // STRATEGY + out.writeObject( strategy ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // STRATEGY + strategy = ( HashingStrategy ) in.readObject(); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + short val = in.readShort(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectShortProcedure() { + private boolean first = true; + public boolean execute( K key, short value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} diff --git a/src/gnu/trove/map/hash/TByteByteHashMap.java b/src/gnu/trove/map/hash/TByteByteHashMap.java new file mode 100644 index 0000000..46868b3 --- /dev/null +++ b/src/gnu/trove/map/hash/TByteByteHashMap.java @@ -0,0 +1,1307 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.function.TByteFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteByteHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteByteIterator; +import gnu.trove.iterator.TByteIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TByteByteMap; +import gnu.trove.procedure.TByteByteProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.set.TByteSet; + +/** + * An open addressed Map implementation for byte keys and byte values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TByteByteHashMap extends TByteByteHash implements TByteByteMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient byte[] _values; + + + /** + * Creates a new TByteByteHashMap instance with the default + * capacity and load factor. + */ + public TByteByteHashMap() { + super(); + } + + + /** + * Creates a new TByteByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteByteHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TByteByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TByteByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a byte value that represents + * null for the Key set. + * @param noEntryValue a byte value that represents + * null for the Value set. + */ + public TByteByteHashMap( int initialCapacity, float loadFactor, + byte noEntryKey, byte noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TByteByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a byte array containing the keys for the matching values. + * @param values a byte array containing the values. + */ + public TByteByteHashMap( byte[] keys, byte[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TByteByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TByteByteMap that will be duplicated. + */ + public TByteByteHashMap( TByteByteMap map ) { + super( map.size() ); + if ( map instanceof TByteByteHashMap ) { + TByteByteHashMap hashmap = ( TByteByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + byte oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public byte put( byte key, byte value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( byte key, byte value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private byte doPut( byte key, byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().byteValue(), entry.getValue().byteValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteByteMap map ) { + ensureCapacity( map.size() ); + TByteByteIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public byte get( byte key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public byte remove( byte key ) { + byte prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public byte[] keys() { + byte[] keys = new byte[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public byte[] keys( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + byte[] states = _states; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TByteByteIterator iterator() { + return new TByteByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TByteProcedure procedure ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TByteByteProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TByteByteProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + byte[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( byte key ) { + return adjustValue( key, ( byte ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( byte key, byte amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( byte key, byte adjust_amount, byte put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TByteSet { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteByteKeyHashIterator( TByteByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteByteHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteByteHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteByteHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteByteMap + *

+ * {@inheritDoc} + */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return no_entry_value != TByteByteHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteByteHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteByteHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteByteHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteByteHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TByteSet)) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TByteProcedure() { + private boolean first = true; + + + public boolean execute( byte key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteByteValueHashIterator( TByteByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteByteHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteByteHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteByteHashMap.this.values( dest ); + } + + + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + byte[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteByteHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TByteByteKeyHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteByteKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TByteByteValueHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteByteValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TByteByteHashIterator extends THashPrimitiveIterator implements TByteByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TByteByteHashMap we will be iterating over. + */ + TByteByteHashIterator( TByteByteHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteByteMap ) ) { + return false; + } + TByteByteMap that = ( TByteByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + byte[] values = _values; + byte[] states = _states; + byte this_no_entry_value = getNoEntryValue(); + byte that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + byte key = _set[i]; + byte that_value = that.get( key ); + byte this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TByteByteProcedure() { + private boolean first = true; + public boolean execute( byte key, byte value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + byte val = in.readByte(); + put(key, val); + } + } +} // TByteByteHashMap diff --git a/src/gnu/trove/map/hash/TByteCharHashMap.java b/src/gnu/trove/map/hash/TByteCharHashMap.java new file mode 100644 index 0000000..03ebbfb --- /dev/null +++ b/src/gnu/trove/map/hash/TByteCharHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TCharCollection; +import gnu.trove.function.TCharFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteCharHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteCharIterator; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TCharIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TByteCharMap; +import gnu.trove.procedure.TByteCharProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.set.TByteSet; + +/** + * An open addressed Map implementation for byte keys and char values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TByteCharHashMap extends TByteCharHash implements TByteCharMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient char[] _values; + + + /** + * Creates a new TByteCharHashMap instance with the default + * capacity and load factor. + */ + public TByteCharHashMap() { + super(); + } + + + /** + * Creates a new TByteCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteCharHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TByteCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TByteCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a byte value that represents + * null for the Key set. + * @param noEntryValue a char value that represents + * null for the Value set. + */ + public TByteCharHashMap( int initialCapacity, float loadFactor, + byte noEntryKey, char noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TByteCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a byte array containing the keys for the matching values. + * @param values a char array containing the values. + */ + public TByteCharHashMap( byte[] keys, char[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TByteCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TByteCharMap that will be duplicated. + */ + public TByteCharHashMap( TByteCharMap map ) { + super( map.size() ); + if ( map instanceof TByteCharHashMap ) { + TByteCharHashMap hashmap = ( TByteCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + char oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public char put( byte key, char value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( byte key, char value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private char doPut( byte key, char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().byteValue(), entry.getValue().charValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteCharMap map ) { + ensureCapacity( map.size() ); + TByteCharIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public char get( byte key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public char remove( byte key ) { + char prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public byte[] keys() { + byte[] keys = new byte[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public byte[] keys( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + byte[] states = _states; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TByteCharIterator iterator() { + return new TByteCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TCharProcedure procedure ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TByteCharProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TByteCharProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + char[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( byte key ) { + return adjustValue( key, ( char ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( byte key, char amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( byte key, char adjust_amount, char put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TByteSet { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteCharKeyHashIterator( TByteCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteCharHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteCharHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteCharHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteCharMap + *

+ * {@inheritDoc} + */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return no_entry_value != TByteCharHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteCharHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteCharHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteCharHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteCharHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TByteSet)) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TByteProcedure() { + private boolean first = true; + + + public boolean execute( byte key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TByteCharValueHashIterator( TByteCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TByteCharHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TByteCharHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TByteCharHashMap.this.values( dest ); + } + + + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + byte[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TByteCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TByteCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TByteCharHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TByteCharKeyHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteCharKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TByteCharValueHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteCharValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TByteCharHashIterator extends THashPrimitiveIterator implements TByteCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TByteCharHashMap we will be iterating over. + */ + TByteCharHashIterator( TByteCharHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteCharMap ) ) { + return false; + } + TByteCharMap that = ( TByteCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + char[] values = _values; + byte[] states = _states; + char this_no_entry_value = getNoEntryValue(); + char that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + byte key = _set[i]; + char that_value = that.get( key ); + char this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TByteCharProcedure() { + private boolean first = true; + public boolean execute( byte key, char value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + char val = in.readChar(); + put(key, val); + } + } +} // TByteCharHashMap diff --git a/src/gnu/trove/map/hash/TByteDoubleHashMap.java b/src/gnu/trove/map/hash/TByteDoubleHashMap.java new file mode 100644 index 0000000..cf4a3d0 --- /dev/null +++ b/src/gnu/trove/map/hash/TByteDoubleHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteDoubleHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteDoubleIterator; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TDoubleIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TByteDoubleMap; +import gnu.trove.procedure.TByteDoubleProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TByteSet; + +/** + * An open addressed Map implementation for byte keys and double values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TByteDoubleHashMap extends TByteDoubleHash implements TByteDoubleMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient double[] _values; + + + /** + * Creates a new TByteDoubleHashMap instance with the default + * capacity and load factor. + */ + public TByteDoubleHashMap() { + super(); + } + + + /** + * Creates a new TByteDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TByteDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TByteDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a byte value that represents + * null for the Key set. + * @param noEntryValue a double value that represents + * null for the Value set. + */ + public TByteDoubleHashMap( int initialCapacity, float loadFactor, + byte noEntryKey, double noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TByteDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a byte array containing the keys for the matching values. + * @param values a double array containing the values. + */ + public TByteDoubleHashMap( byte[] keys, double[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TByteDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TByteDoubleMap that will be duplicated. + */ + public TByteDoubleHashMap( TByteDoubleMap map ) { + super( map.size() ); + if ( map instanceof TByteDoubleHashMap ) { + TByteDoubleHashMap hashmap = ( TByteDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + double oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public double put( byte key, double value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( byte key, double value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private double doPut( byte key, double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().byteValue(), entry.getValue().doubleValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteDoubleMap map ) { + ensureCapacity( map.size() ); + TByteDoubleIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public double get( byte key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public double remove( byte key ) { + double prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public byte[] keys() { + byte[] keys = new byte[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public byte[] keys( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + byte[] states = _states; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TByteDoubleIterator iterator() { + return new TByteDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TByteDoubleProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TByteDoubleProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + double[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( byte key ) { + return adjustValue( key, ( double ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( byte key, double amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( byte key, double adjust_amount, double put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TByteSet { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteDoubleKeyHashIterator( TByteDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteDoubleHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteDoubleHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteDoubleHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteDoubleMap + *

+ * {@inheritDoc} + */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return no_entry_value != TByteDoubleHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteDoubleHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteDoubleHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteDoubleHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteDoubleHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TByteSet)) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TByteProcedure() { + private boolean first = true; + + + public boolean execute( byte key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TByteDoubleValueHashIterator( TByteDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TByteDoubleHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TByteDoubleHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TByteDoubleHashMap.this.values( dest ); + } + + + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + byte[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TByteDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TByteDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TByteDoubleHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TByteDoubleKeyHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteDoubleKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TByteDoubleValueHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteDoubleValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TByteDoubleHashIterator extends THashPrimitiveIterator implements TByteDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TByteDoubleHashMap we will be iterating over. + */ + TByteDoubleHashIterator( TByteDoubleHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteDoubleMap ) ) { + return false; + } + TByteDoubleMap that = ( TByteDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + double[] values = _values; + byte[] states = _states; + double this_no_entry_value = getNoEntryValue(); + double that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + byte key = _set[i]; + double that_value = that.get( key ); + double this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TByteDoubleProcedure() { + private boolean first = true; + public boolean execute( byte key, double value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + double val = in.readDouble(); + put(key, val); + } + } +} // TByteDoubleHashMap diff --git a/src/gnu/trove/map/hash/TByteFloatHashMap.java b/src/gnu/trove/map/hash/TByteFloatHashMap.java new file mode 100644 index 0000000..a06d8c5 --- /dev/null +++ b/src/gnu/trove/map/hash/TByteFloatHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TFloatCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteFloatHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteFloatIterator; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TFloatIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TByteFloatMap; +import gnu.trove.procedure.TByteFloatProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TByteSet; + +/** + * An open addressed Map implementation for byte keys and float values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TByteFloatHashMap extends TByteFloatHash implements TByteFloatMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient float[] _values; + + + /** + * Creates a new TByteFloatHashMap instance with the default + * capacity and load factor. + */ + public TByteFloatHashMap() { + super(); + } + + + /** + * Creates a new TByteFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TByteFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TByteFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a byte value that represents + * null for the Key set. + * @param noEntryValue a float value that represents + * null for the Value set. + */ + public TByteFloatHashMap( int initialCapacity, float loadFactor, + byte noEntryKey, float noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TByteFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a byte array containing the keys for the matching values. + * @param values a float array containing the values. + */ + public TByteFloatHashMap( byte[] keys, float[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TByteFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TByteFloatMap that will be duplicated. + */ + public TByteFloatHashMap( TByteFloatMap map ) { + super( map.size() ); + if ( map instanceof TByteFloatHashMap ) { + TByteFloatHashMap hashmap = ( TByteFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + float oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public float put( byte key, float value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( byte key, float value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private float doPut( byte key, float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().byteValue(), entry.getValue().floatValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteFloatMap map ) { + ensureCapacity( map.size() ); + TByteFloatIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public float get( byte key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public float remove( byte key ) { + float prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public byte[] keys() { + byte[] keys = new byte[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public byte[] keys( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + byte[] states = _states; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TByteFloatIterator iterator() { + return new TByteFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TFloatProcedure procedure ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TByteFloatProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TByteFloatProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + float[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( byte key ) { + return adjustValue( key, ( float ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( byte key, float amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( byte key, float adjust_amount, float put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TByteSet { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteFloatKeyHashIterator( TByteFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteFloatHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteFloatHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteFloatHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteFloatMap + *

+ * {@inheritDoc} + */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return no_entry_value != TByteFloatHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteFloatHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteFloatHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteFloatHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteFloatHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TByteSet)) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TByteProcedure() { + private boolean first = true; + + + public boolean execute( byte key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TByteFloatValueHashIterator( TByteFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TByteFloatHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TByteFloatHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TByteFloatHashMap.this.values( dest ); + } + + + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + byte[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TByteFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TByteFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TByteFloatHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TByteFloatKeyHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteFloatKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TByteFloatValueHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteFloatValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TByteFloatHashIterator extends THashPrimitiveIterator implements TByteFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TByteFloatHashMap we will be iterating over. + */ + TByteFloatHashIterator( TByteFloatHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteFloatMap ) ) { + return false; + } + TByteFloatMap that = ( TByteFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + float[] values = _values; + byte[] states = _states; + float this_no_entry_value = getNoEntryValue(); + float that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + byte key = _set[i]; + float that_value = that.get( key ); + float this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TByteFloatProcedure() { + private boolean first = true; + public boolean execute( byte key, float value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + float val = in.readFloat(); + put(key, val); + } + } +} // TByteFloatHashMap diff --git a/src/gnu/trove/map/hash/TByteIntHashMap.java b/src/gnu/trove/map/hash/TByteIntHashMap.java new file mode 100644 index 0000000..8a4861d --- /dev/null +++ b/src/gnu/trove/map/hash/TByteIntHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TIntCollection; +import gnu.trove.function.TIntFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteIntHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteIntIterator; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TIntIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TByteIntMap; +import gnu.trove.procedure.TByteIntProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TByteSet; + +/** + * An open addressed Map implementation for byte keys and int values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TByteIntHashMap extends TByteIntHash implements TByteIntMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient int[] _values; + + + /** + * Creates a new TByteIntHashMap instance with the default + * capacity and load factor. + */ + public TByteIntHashMap() { + super(); + } + + + /** + * Creates a new TByteIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteIntHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TByteIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TByteIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a byte value that represents + * null for the Key set. + * @param noEntryValue a int value that represents + * null for the Value set. + */ + public TByteIntHashMap( int initialCapacity, float loadFactor, + byte noEntryKey, int noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TByteIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a byte array containing the keys for the matching values. + * @param values a int array containing the values. + */ + public TByteIntHashMap( byte[] keys, int[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TByteIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TByteIntMap that will be duplicated. + */ + public TByteIntHashMap( TByteIntMap map ) { + super( map.size() ); + if ( map instanceof TByteIntHashMap ) { + TByteIntHashMap hashmap = ( TByteIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + int oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public int put( byte key, int value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( byte key, int value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private int doPut( byte key, int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().byteValue(), entry.getValue().intValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteIntMap map ) { + ensureCapacity( map.size() ); + TByteIntIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public int get( byte key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public int remove( byte key ) { + int prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public byte[] keys() { + byte[] keys = new byte[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public byte[] keys( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + byte[] states = _states; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TByteIntIterator iterator() { + return new TByteIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TIntProcedure procedure ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TByteIntProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TByteIntProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + int[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( byte key ) { + return adjustValue( key, ( int ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( byte key, int amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( byte key, int adjust_amount, int put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TByteSet { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteIntKeyHashIterator( TByteIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteIntHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteIntHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteIntHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteIntMap + *

+ * {@inheritDoc} + */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return no_entry_value != TByteIntHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteIntHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteIntHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteIntHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteIntHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TByteSet)) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TByteProcedure() { + private boolean first = true; + + + public boolean execute( byte key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TByteIntValueHashIterator( TByteIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TByteIntHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TByteIntHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TByteIntHashMap.this.values( dest ); + } + + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + byte[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TByteIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TByteIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TByteIntHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TByteIntKeyHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteIntKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TByteIntValueHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteIntValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TByteIntHashIterator extends THashPrimitiveIterator implements TByteIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TByteIntHashMap we will be iterating over. + */ + TByteIntHashIterator( TByteIntHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteIntMap ) ) { + return false; + } + TByteIntMap that = ( TByteIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + int[] values = _values; + byte[] states = _states; + int this_no_entry_value = getNoEntryValue(); + int that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + byte key = _set[i]; + int that_value = that.get( key ); + int this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TByteIntProcedure() { + private boolean first = true; + public boolean execute( byte key, int value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + int val = in.readInt(); + put(key, val); + } + } +} // TByteIntHashMap diff --git a/src/gnu/trove/map/hash/TByteLongHashMap.java b/src/gnu/trove/map/hash/TByteLongHashMap.java new file mode 100644 index 0000000..86ceb72 --- /dev/null +++ b/src/gnu/trove/map/hash/TByteLongHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TLongCollection; +import gnu.trove.function.TLongFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteLongHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TByteLongIterator; +import gnu.trove.iterator.TLongIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TByteLongMap; +import gnu.trove.procedure.TByteLongProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TByteSet; + +/** + * An open addressed Map implementation for byte keys and long values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TByteLongHashMap extends TByteLongHash implements TByteLongMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient long[] _values; + + + /** + * Creates a new TByteLongHashMap instance with the default + * capacity and load factor. + */ + public TByteLongHashMap() { + super(); + } + + + /** + * Creates a new TByteLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteLongHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TByteLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TByteLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a byte value that represents + * null for the Key set. + * @param noEntryValue a long value that represents + * null for the Value set. + */ + public TByteLongHashMap( int initialCapacity, float loadFactor, + byte noEntryKey, long noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TByteLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a byte array containing the keys for the matching values. + * @param values a long array containing the values. + */ + public TByteLongHashMap( byte[] keys, long[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TByteLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TByteLongMap that will be duplicated. + */ + public TByteLongHashMap( TByteLongMap map ) { + super( map.size() ); + if ( map instanceof TByteLongHashMap ) { + TByteLongHashMap hashmap = ( TByteLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + long oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public long put( byte key, long value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( byte key, long value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private long doPut( byte key, long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().byteValue(), entry.getValue().longValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteLongMap map ) { + ensureCapacity( map.size() ); + TByteLongIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public long get( byte key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public long remove( byte key ) { + long prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public byte[] keys() { + byte[] keys = new byte[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public byte[] keys( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + byte[] states = _states; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TByteLongIterator iterator() { + return new TByteLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TLongProcedure procedure ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TByteLongProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TByteLongProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + long[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( byte key ) { + return adjustValue( key, ( long ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( byte key, long amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( byte key, long adjust_amount, long put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TByteSet { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteLongKeyHashIterator( TByteLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteLongHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteLongHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteLongHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteLongMap + *

+ * {@inheritDoc} + */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return no_entry_value != TByteLongHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteLongHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteLongHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteLongHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteLongHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TByteSet)) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TByteProcedure() { + private boolean first = true; + + + public boolean execute( byte key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TByteLongValueHashIterator( TByteLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TByteLongHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TByteLongHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TByteLongHashMap.this.values( dest ); + } + + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + byte[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TByteLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TByteLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TByteLongHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TByteLongKeyHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteLongKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TByteLongValueHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteLongValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TByteLongHashIterator extends THashPrimitiveIterator implements TByteLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TByteLongHashMap we will be iterating over. + */ + TByteLongHashIterator( TByteLongHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteLongMap ) ) { + return false; + } + TByteLongMap that = ( TByteLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + long[] values = _values; + byte[] states = _states; + long this_no_entry_value = getNoEntryValue(); + long that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + byte key = _set[i]; + long that_value = that.get( key ); + long this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TByteLongProcedure() { + private boolean first = true; + public boolean execute( byte key, long value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + long val = in.readLong(); + put(key, val); + } + } +} // TByteLongHashMap diff --git a/src/gnu/trove/map/hash/TByteObjectHashMap.java b/src/gnu/trove/map/hash/TByteObjectHashMap.java new file mode 100644 index 0000000..0ea6469 --- /dev/null +++ b/src/gnu/trove/map/hash/TByteObjectHashMap.java @@ -0,0 +1,1037 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import gnu.trove.TByteCollection; +import gnu.trove.function.TObjectFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TByteObjectIterator; +import gnu.trove.map.TByteObjectMap; +import gnu.trove.procedure.TByteObjectProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.set.TByteSet; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for byte keys and Object values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TByteObjectHashMap extends TByteHash implements + TByteObjectMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TByteObjectProcedure PUT_ALL_PROC = new TByteObjectProcedure() { + public boolean execute( byte key, V value) { + put( key, value ); + return true; + } + }; + + /** the values of the map */ + protected transient V[] _values; + + /** the value that represents null in the key set. */ + protected byte no_entry_key; + + + /** + * Creates a new TByteObjectHashMap instance with the default + * capacity and load factor. + */ + public TByteObjectHashMap() { + super(); + } + + + /** + * Creates a new TByteObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteObjectHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TByteObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteObjectHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_key = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TByteObjectHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryKey the value used to represent null in the key set. + */ + public TByteObjectHashMap( int initialCapacity, float loadFactor, byte noEntryKey ) { + super( initialCapacity, loadFactor ); + no_entry_key = noEntryKey; + } + + + /** + * Creates a new TByteObjectHashMap that contains the entries + * in the map passed to it. + * + * @param map the TByteObjectMap to be copied. + */ + public TByteObjectHashMap( TByteObjectMap map ) { + this( map.size(), 0.5f, map.getNoEntryKey() ); + putAll( map ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = ( V[] ) new Object[capacity]; + return capacity; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + V oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = (V[]) new Object[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey(o); + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public byte getNoEntryKey() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( Object val ) { + byte[] states = _states; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && null == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && + ( val == vals[i] || val.equals( vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + /** {@inheritDoc} */ + public V get( byte key ) { + int index = index( key ); + return index < 0 ? null : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public V put( byte key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public V putIfAbsent( byte key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + @SuppressWarnings({}) + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public V remove( byte key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteObjectMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _states, 0, _states.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + // Views + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public byte[] keys() { + byte[] keys = new byte[size()]; + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public byte[] keys( byte[] dest ) { + if ( dest.length < _size ) { + dest = new byte[_size]; + } + + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = k[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public Collection valueCollection() { + return new ValueView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public Object[] values() { + Object[] vals = new Object[size()]; + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public V[] values( V[] dest ) { + if ( dest.length < _size ) { + dest = ( V[] ) java.lang.reflect.Array.newInstance( + dest.getClass().getComponentType(), _size); + } + + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = ( V ) v[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public TByteObjectIterator iterator() { + return new TByteObjectHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TObjectProcedure procedure ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean forEachEntry( TByteObjectProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (states[i] == FULL && ! procedure.execute(keys[i],values[i])) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainEntries( TByteObjectProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public void transformValues( TObjectFunction function ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** {@inheritDoc} */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteObjectMap ) ) { + return false; + } + TByteObjectMap that = ( TByteObjectMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TByteObjectIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + byte key = iter.key(); + Object value = iter.value(); + if ( value == null ) { + if ( !( that.get( key ) == null && that.containsKey( key ) ) ) { + return false; + } + } else { + if ( !value.equals( that.get( key ) ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + V[] values = _values; + byte[] states = _states; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + ( values[i] == null ? 0 : values[i].hashCode() ); + } + } + return hashcode; + } + + + class KeyView implements TByteSet { + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _size == 0; + } + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteObjectHashMap.this.containsKey( entry ); + } + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteHashIterator( TByteObjectHashMap.this ); + } + + /** {@inheritDoc} */ + public byte[] toArray() { + return keys(); + } + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return keys( dest ); + } + + /** {@inheritDoc} */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return null != TByteObjectHashMap.this.remove( entry ); + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( ! TByteObjectHashMap.this.containsKey( + ( ( Byte ) element ).byteValue() ) ) { + + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + if ( collection == this ) { + return true; + } + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteObjectHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteObjectHashMap.this.containsKey( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + //noinspection SuspiciousMethodCalls + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TByteObjectHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteObjectHashMap.this.forEachKey( procedure ); + } + + /** {@inheritDoc) */ + public boolean equals( Object other ) { + if (! ( other instanceof TByteSet ) ) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( first ) first = false; + else buf.append( "," ); + buf.append( _set[i] ); + } + } + return buf.toString(); + } + + + class TByteHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** the collection on which the iterator operates */ + private final TByteHash _hash; + + /** {@inheritDoc} */ + public TByteHashIterator( TByteHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({}) + public Iterator iterator() { + return new TByteObjectValueHashIterator( TByteObjectHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + public boolean removeElement( V value ) { + V[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + if ( value == values[i] || + ( null != values[i] && values[i].equals( value ) ) ) { + removeAt( i ); + return true; + } + } + } + return false; + } + + class TByteObjectValueHashIterator extends THashPrimitiveIterator + implements Iterator { + + @SuppressWarnings("rawtypes") + protected final TByteObjectHashMap _map; + + @SuppressWarnings("rawtypes") + public TByteObjectValueHashIterator( TByteObjectHashMap map ) { + super( map ); + _map = map; + } + + @SuppressWarnings("unchecked") + protected V objectAtIndex( int index ) { + byte[] states = _states; + Object value = _map._values[index]; + if ( states[index] != FULL ) { + return null; + } + return ( V ) value; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public V next() { + moveToNextIndex(); + return ( V ) _map._values[_index]; + } + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TByteObjectHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TByteObjectHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TByteObjectHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + @SuppressWarnings("hiding") + class TByteObjectHashIterator extends THashPrimitiveIterator + implements TByteObjectIterator { + + /** the collection being iterated over */ + private final TByteObjectHashMap _map; + + /** + * Creates an iterator over the specified map + * + * @param map map to iterate over. + */ + public TByteObjectHashIterator( TByteObjectHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _map._set[_index]; + } + + /** {@inheritDoc} */ + public V value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public V setValue( V val ) { + V old = value(); + _map._values[_index] = val; + return old; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeByte( no_entry_key ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readByte(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + V val = (V) in.readObject(); + put(key, val); + } + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TByteObjectProcedure() { + private boolean first = true; + public boolean execute(byte key, Object value) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } +} // TByteObjectHashMap diff --git a/src/gnu/trove/map/hash/TByteShortHashMap.java b/src/gnu/trove/map/hash/TByteShortHashMap.java new file mode 100644 index 0000000..a1e33d2 --- /dev/null +++ b/src/gnu/trove/map/hash/TByteShortHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TShortCollection; +import gnu.trove.function.TShortFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TByteShortHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TByteShortIterator; +import gnu.trove.iterator.TShortIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TByteShortMap; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TByteShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TByteSet; + +/** + * An open addressed Map implementation for byte keys and short values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TByteShortHashMap extends TByteShortHash implements TByteShortMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient short[] _values; + + + /** + * Creates a new TByteShortHashMap instance with the default + * capacity and load factor. + */ + public TByteShortHashMap() { + super(); + } + + + /** + * Creates a new TByteShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteShortHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TByteShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TByteShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TByteShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a byte value that represents + * null for the Key set. + * @param noEntryValue a short value that represents + * null for the Value set. + */ + public TByteShortHashMap( int initialCapacity, float loadFactor, + byte noEntryKey, short noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TByteShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a byte array containing the keys for the matching values. + * @param values a short array containing the values. + */ + public TByteShortHashMap( byte[] keys, short[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TByteShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TByteShortMap that will be duplicated. + */ + public TByteShortHashMap( TByteShortMap map ) { + super( map.size() ); + if ( map instanceof TByteShortHashMap ) { + TByteShortHashMap hashmap = ( TByteShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldKeys[] = _set; + short oldVals[] = _values; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _values = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public short put( byte key, short value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( byte key, short value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private short doPut( byte key, short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().byteValue(), entry.getValue().shortValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TByteShortMap map ) { + ensureCapacity( map.size() ); + TByteShortIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public short get( byte key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public short remove( byte key ) { + short prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TByteSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public byte[] keys() { + byte[] keys = new byte[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + byte[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public byte[] keys( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + byte[] states = _states; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( byte key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TByteShortIterator iterator() { + return new TByteShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TByteProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TShortProcedure procedure ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TByteShortProcedure procedure ) { + byte[] states = _states; + byte[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TByteShortProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + byte[] keys = _set; + short[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( byte key ) { + return adjustValue( key, ( short ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( byte key, short amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( byte key, short adjust_amount, short put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TByteSet { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteShortKeyHashIterator( TByteShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TByteShortHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TByteShortHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TByteShortHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteShortMap + *

+ * {@inheritDoc} + */ + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + return no_entry_value != TByteShortHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TByteShortHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteShortHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TByteShortHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TByteShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TByteShortHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TByteSet)) { + return false; + } + final TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TByteProcedure() { + private boolean first = true; + + + public boolean execute( byte key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TByteShortValueHashIterator( TByteShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TByteShortHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TByteShortHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TByteShortHashMap.this.values( dest ); + } + + + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + byte[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TByteShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TByteShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TByteShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TByteShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TByteShortHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TByteShortKeyHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteShortKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TByteShortValueHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TByteShortValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TByteShortHashIterator extends THashPrimitiveIterator implements TByteShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TByteShortHashMap we will be iterating over. + */ + TByteShortHashIterator( TByteShortHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public byte key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TByteShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteShortMap ) ) { + return false; + } + TByteShortMap that = ( TByteShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + short[] values = _values; + byte[] states = _states; + short this_no_entry_value = getNoEntryValue(); + short that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + byte key = _set[i]; + short that_value = that.get( key ); + short this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TByteShortProcedure() { + private boolean first = true; + public boolean execute( byte key, short value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + byte key = in.readByte(); + short val = in.readShort(); + put(key, val); + } + } +} // TByteShortHashMap diff --git a/src/gnu/trove/map/hash/TCharByteHashMap.java b/src/gnu/trove/map/hash/TCharByteHashMap.java new file mode 100644 index 0000000..99590bb --- /dev/null +++ b/src/gnu/trove/map/hash/TCharByteHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TCharCollection; +import gnu.trove.function.TByteFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharByteHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TCharByteIterator; +import gnu.trove.iterator.TCharIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TCharByteMap; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TCharByteProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.set.TCharSet; + +/** + * An open addressed Map implementation for char keys and byte values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TCharByteHashMap extends TCharByteHash implements TCharByteMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient byte[] _values; + + + /** + * Creates a new TCharByteHashMap instance with the default + * capacity and load factor. + */ + public TCharByteHashMap() { + super(); + } + + + /** + * Creates a new TCharByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharByteHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TCharByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCharByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a char value that represents + * null for the Key set. + * @param noEntryValue a byte value that represents + * null for the Value set. + */ + public TCharByteHashMap( int initialCapacity, float loadFactor, + char noEntryKey, byte noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TCharByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a char array containing the keys for the matching values. + * @param values a byte array containing the values. + */ + public TCharByteHashMap( char[] keys, byte[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TCharByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TCharByteMap that will be duplicated. + */ + public TCharByteHashMap( TCharByteMap map ) { + super( map.size() ); + if ( map instanceof TCharByteHashMap ) { + TCharByteHashMap hashmap = ( TCharByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + byte oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public byte put( char key, byte value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( char key, byte value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private byte doPut( char key, byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().charValue(), entry.getValue().byteValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharByteMap map ) { + ensureCapacity( map.size() ); + TCharByteIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public byte get( char key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public byte remove( char key ) { + byte prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public char[] keys() { + char[] keys = new char[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public char[] keys( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + byte[] states = _states; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TCharByteIterator iterator() { + return new TCharByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TByteProcedure procedure ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TCharByteProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TCharByteProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + byte[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( char key ) { + return adjustValue( key, ( byte ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( char key, byte amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( char key, byte adjust_amount, byte put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TCharSet { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharByteKeyHashIterator( TCharByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharByteHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharByteHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharByteHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharByteMap + *

+ * {@inheritDoc} + */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return no_entry_value != TCharByteHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharByteHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharByteHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharByteHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharByteHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TCharSet)) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TCharProcedure() { + private boolean first = true; + + + public boolean execute( char key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TCharByteValueHashIterator( TCharByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TCharByteHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TCharByteHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TCharByteHashMap.this.values( dest ); + } + + + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + char[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TCharByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TCharByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TCharByteHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TCharByteKeyHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharByteKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TCharByteValueHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharByteValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TCharByteHashIterator extends THashPrimitiveIterator implements TCharByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TCharByteHashMap we will be iterating over. + */ + TCharByteHashIterator( TCharByteHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharByteMap ) ) { + return false; + } + TCharByteMap that = ( TCharByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + byte[] values = _values; + byte[] states = _states; + byte this_no_entry_value = getNoEntryValue(); + byte that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + char key = _set[i]; + byte that_value = that.get( key ); + byte this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TCharByteProcedure() { + private boolean first = true; + public boolean execute( char key, byte value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + byte val = in.readByte(); + put(key, val); + } + } +} // TCharByteHashMap diff --git a/src/gnu/trove/map/hash/TCharCharHashMap.java b/src/gnu/trove/map/hash/TCharCharHashMap.java new file mode 100644 index 0000000..3093d1c --- /dev/null +++ b/src/gnu/trove/map/hash/TCharCharHashMap.java @@ -0,0 +1,1307 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.function.TCharFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharCharHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharCharIterator; +import gnu.trove.iterator.TCharIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TCharCharMap; +import gnu.trove.procedure.TCharCharProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.set.TCharSet; + +/** + * An open addressed Map implementation for char keys and char values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TCharCharHashMap extends TCharCharHash implements TCharCharMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient char[] _values; + + + /** + * Creates a new TCharCharHashMap instance with the default + * capacity and load factor. + */ + public TCharCharHashMap() { + super(); + } + + + /** + * Creates a new TCharCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharCharHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TCharCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCharCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a char value that represents + * null for the Key set. + * @param noEntryValue a char value that represents + * null for the Value set. + */ + public TCharCharHashMap( int initialCapacity, float loadFactor, + char noEntryKey, char noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TCharCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a char array containing the keys for the matching values. + * @param values a char array containing the values. + */ + public TCharCharHashMap( char[] keys, char[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TCharCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TCharCharMap that will be duplicated. + */ + public TCharCharHashMap( TCharCharMap map ) { + super( map.size() ); + if ( map instanceof TCharCharHashMap ) { + TCharCharHashMap hashmap = ( TCharCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + char oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public char put( char key, char value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( char key, char value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private char doPut( char key, char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().charValue(), entry.getValue().charValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharCharMap map ) { + ensureCapacity( map.size() ); + TCharCharIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public char get( char key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public char remove( char key ) { + char prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public char[] keys() { + char[] keys = new char[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public char[] keys( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + byte[] states = _states; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TCharCharIterator iterator() { + return new TCharCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TCharProcedure procedure ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TCharCharProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TCharCharProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + char[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( char key ) { + return adjustValue( key, ( char ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( char key, char amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( char key, char adjust_amount, char put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TCharSet { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharCharKeyHashIterator( TCharCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharCharHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharCharHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharCharHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharCharMap + *

+ * {@inheritDoc} + */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return no_entry_value != TCharCharHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharCharHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharCharHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharCharHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharCharHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TCharSet)) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TCharProcedure() { + private boolean first = true; + + + public boolean execute( char key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharCharValueHashIterator( TCharCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharCharHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharCharHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharCharHashMap.this.values( dest ); + } + + + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + char[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharCharHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TCharCharKeyHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharCharKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TCharCharValueHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharCharValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TCharCharHashIterator extends THashPrimitiveIterator implements TCharCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TCharCharHashMap we will be iterating over. + */ + TCharCharHashIterator( TCharCharHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharCharMap ) ) { + return false; + } + TCharCharMap that = ( TCharCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + char[] values = _values; + byte[] states = _states; + char this_no_entry_value = getNoEntryValue(); + char that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + char key = _set[i]; + char that_value = that.get( key ); + char this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TCharCharProcedure() { + private boolean first = true; + public boolean execute( char key, char value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + char val = in.readChar(); + put(key, val); + } + } +} // TCharCharHashMap diff --git a/src/gnu/trove/map/hash/TCharDoubleHashMap.java b/src/gnu/trove/map/hash/TCharDoubleHashMap.java new file mode 100644 index 0000000..6fe53a6 --- /dev/null +++ b/src/gnu/trove/map/hash/TCharDoubleHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharDoubleHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharDoubleIterator; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TDoubleIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TCharDoubleMap; +import gnu.trove.procedure.TCharDoubleProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TCharSet; + +/** + * An open addressed Map implementation for char keys and double values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TCharDoubleHashMap extends TCharDoubleHash implements TCharDoubleMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient double[] _values; + + + /** + * Creates a new TCharDoubleHashMap instance with the default + * capacity and load factor. + */ + public TCharDoubleHashMap() { + super(); + } + + + /** + * Creates a new TCharDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TCharDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCharDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a char value that represents + * null for the Key set. + * @param noEntryValue a double value that represents + * null for the Value set. + */ + public TCharDoubleHashMap( int initialCapacity, float loadFactor, + char noEntryKey, double noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TCharDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a char array containing the keys for the matching values. + * @param values a double array containing the values. + */ + public TCharDoubleHashMap( char[] keys, double[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TCharDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TCharDoubleMap that will be duplicated. + */ + public TCharDoubleHashMap( TCharDoubleMap map ) { + super( map.size() ); + if ( map instanceof TCharDoubleHashMap ) { + TCharDoubleHashMap hashmap = ( TCharDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + double oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public double put( char key, double value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( char key, double value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private double doPut( char key, double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().charValue(), entry.getValue().doubleValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharDoubleMap map ) { + ensureCapacity( map.size() ); + TCharDoubleIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public double get( char key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public double remove( char key ) { + double prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public char[] keys() { + char[] keys = new char[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public char[] keys( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + byte[] states = _states; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TCharDoubleIterator iterator() { + return new TCharDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TCharDoubleProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TCharDoubleProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + double[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( char key ) { + return adjustValue( key, ( double ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( char key, double amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( char key, double adjust_amount, double put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TCharSet { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharDoubleKeyHashIterator( TCharDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharDoubleHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharDoubleHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharDoubleHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharDoubleMap + *

+ * {@inheritDoc} + */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return no_entry_value != TCharDoubleHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharDoubleHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharDoubleHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharDoubleHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharDoubleHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TCharSet)) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TCharProcedure() { + private boolean first = true; + + + public boolean execute( char key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TCharDoubleValueHashIterator( TCharDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TCharDoubleHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TCharDoubleHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TCharDoubleHashMap.this.values( dest ); + } + + + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + char[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TCharDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TCharDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TCharDoubleHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TCharDoubleKeyHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharDoubleKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TCharDoubleValueHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharDoubleValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TCharDoubleHashIterator extends THashPrimitiveIterator implements TCharDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TCharDoubleHashMap we will be iterating over. + */ + TCharDoubleHashIterator( TCharDoubleHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharDoubleMap ) ) { + return false; + } + TCharDoubleMap that = ( TCharDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + double[] values = _values; + byte[] states = _states; + double this_no_entry_value = getNoEntryValue(); + double that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + char key = _set[i]; + double that_value = that.get( key ); + double this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TCharDoubleProcedure() { + private boolean first = true; + public boolean execute( char key, double value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + double val = in.readDouble(); + put(key, val); + } + } +} // TCharDoubleHashMap diff --git a/src/gnu/trove/map/hash/TCharFloatHashMap.java b/src/gnu/trove/map/hash/TCharFloatHashMap.java new file mode 100644 index 0000000..d451c87 --- /dev/null +++ b/src/gnu/trove/map/hash/TCharFloatHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.TFloatCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharFloatHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharFloatIterator; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TFloatIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TCharFloatMap; +import gnu.trove.procedure.TCharFloatProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TCharSet; + +/** + * An open addressed Map implementation for char keys and float values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TCharFloatHashMap extends TCharFloatHash implements TCharFloatMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient float[] _values; + + + /** + * Creates a new TCharFloatHashMap instance with the default + * capacity and load factor. + */ + public TCharFloatHashMap() { + super(); + } + + + /** + * Creates a new TCharFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TCharFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCharFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a char value that represents + * null for the Key set. + * @param noEntryValue a float value that represents + * null for the Value set. + */ + public TCharFloatHashMap( int initialCapacity, float loadFactor, + char noEntryKey, float noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TCharFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a char array containing the keys for the matching values. + * @param values a float array containing the values. + */ + public TCharFloatHashMap( char[] keys, float[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TCharFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TCharFloatMap that will be duplicated. + */ + public TCharFloatHashMap( TCharFloatMap map ) { + super( map.size() ); + if ( map instanceof TCharFloatHashMap ) { + TCharFloatHashMap hashmap = ( TCharFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + float oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public float put( char key, float value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( char key, float value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private float doPut( char key, float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().charValue(), entry.getValue().floatValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharFloatMap map ) { + ensureCapacity( map.size() ); + TCharFloatIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public float get( char key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public float remove( char key ) { + float prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public char[] keys() { + char[] keys = new char[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public char[] keys( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + byte[] states = _states; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TCharFloatIterator iterator() { + return new TCharFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TFloatProcedure procedure ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TCharFloatProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TCharFloatProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + float[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( char key ) { + return adjustValue( key, ( float ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( char key, float amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( char key, float adjust_amount, float put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TCharSet { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharFloatKeyHashIterator( TCharFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharFloatHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharFloatHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharFloatHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharFloatMap + *

+ * {@inheritDoc} + */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return no_entry_value != TCharFloatHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharFloatHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharFloatHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharFloatHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharFloatHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TCharSet)) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TCharProcedure() { + private boolean first = true; + + + public boolean execute( char key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TCharFloatValueHashIterator( TCharFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TCharFloatHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TCharFloatHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TCharFloatHashMap.this.values( dest ); + } + + + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + char[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TCharFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TCharFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TCharFloatHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TCharFloatKeyHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharFloatKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TCharFloatValueHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharFloatValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TCharFloatHashIterator extends THashPrimitiveIterator implements TCharFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TCharFloatHashMap we will be iterating over. + */ + TCharFloatHashIterator( TCharFloatHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharFloatMap ) ) { + return false; + } + TCharFloatMap that = ( TCharFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + float[] values = _values; + byte[] states = _states; + float this_no_entry_value = getNoEntryValue(); + float that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + char key = _set[i]; + float that_value = that.get( key ); + float this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TCharFloatProcedure() { + private boolean first = true; + public boolean execute( char key, float value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + float val = in.readFloat(); + put(key, val); + } + } +} // TCharFloatHashMap diff --git a/src/gnu/trove/map/hash/TCharIntHashMap.java b/src/gnu/trove/map/hash/TCharIntHashMap.java new file mode 100644 index 0000000..9537f33 --- /dev/null +++ b/src/gnu/trove/map/hash/TCharIntHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.TIntCollection; +import gnu.trove.function.TIntFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharIntHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharIntIterator; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TIntIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TCharIntMap; +import gnu.trove.procedure.TCharIntProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TCharSet; + +/** + * An open addressed Map implementation for char keys and int values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TCharIntHashMap extends TCharIntHash implements TCharIntMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient int[] _values; + + + /** + * Creates a new TCharIntHashMap instance with the default + * capacity and load factor. + */ + public TCharIntHashMap() { + super(); + } + + + /** + * Creates a new TCharIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharIntHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TCharIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCharIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a char value that represents + * null for the Key set. + * @param noEntryValue a int value that represents + * null for the Value set. + */ + public TCharIntHashMap( int initialCapacity, float loadFactor, + char noEntryKey, int noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TCharIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a char array containing the keys for the matching values. + * @param values a int array containing the values. + */ + public TCharIntHashMap( char[] keys, int[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TCharIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TCharIntMap that will be duplicated. + */ + public TCharIntHashMap( TCharIntMap map ) { + super( map.size() ); + if ( map instanceof TCharIntHashMap ) { + TCharIntHashMap hashmap = ( TCharIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + int oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public int put( char key, int value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( char key, int value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private int doPut( char key, int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().charValue(), entry.getValue().intValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharIntMap map ) { + ensureCapacity( map.size() ); + TCharIntIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public int get( char key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public int remove( char key ) { + int prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public char[] keys() { + char[] keys = new char[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public char[] keys( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + byte[] states = _states; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TCharIntIterator iterator() { + return new TCharIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TIntProcedure procedure ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TCharIntProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TCharIntProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + int[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( char key ) { + return adjustValue( key, ( int ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( char key, int amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( char key, int adjust_amount, int put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TCharSet { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharIntKeyHashIterator( TCharIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharIntHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharIntHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharIntHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharIntMap + *

+ * {@inheritDoc} + */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return no_entry_value != TCharIntHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharIntHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharIntHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharIntHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharIntHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TCharSet)) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TCharProcedure() { + private boolean first = true; + + + public boolean execute( char key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TCharIntValueHashIterator( TCharIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TCharIntHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TCharIntHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TCharIntHashMap.this.values( dest ); + } + + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + char[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TCharIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TCharIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TCharIntHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TCharIntKeyHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharIntKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TCharIntValueHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharIntValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TCharIntHashIterator extends THashPrimitiveIterator implements TCharIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TCharIntHashMap we will be iterating over. + */ + TCharIntHashIterator( TCharIntHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharIntMap ) ) { + return false; + } + TCharIntMap that = ( TCharIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + int[] values = _values; + byte[] states = _states; + int this_no_entry_value = getNoEntryValue(); + int that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + char key = _set[i]; + int that_value = that.get( key ); + int this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TCharIntProcedure() { + private boolean first = true; + public boolean execute( char key, int value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + int val = in.readInt(); + put(key, val); + } + } +} // TCharIntHashMap diff --git a/src/gnu/trove/map/hash/TCharLongHashMap.java b/src/gnu/trove/map/hash/TCharLongHashMap.java new file mode 100644 index 0000000..edca2c3 --- /dev/null +++ b/src/gnu/trove/map/hash/TCharLongHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.TLongCollection; +import gnu.trove.function.TLongFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharLongHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TCharLongIterator; +import gnu.trove.iterator.TLongIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TCharLongMap; +import gnu.trove.procedure.TCharLongProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TCharSet; + +/** + * An open addressed Map implementation for char keys and long values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TCharLongHashMap extends TCharLongHash implements TCharLongMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient long[] _values; + + + /** + * Creates a new TCharLongHashMap instance with the default + * capacity and load factor. + */ + public TCharLongHashMap() { + super(); + } + + + /** + * Creates a new TCharLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharLongHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TCharLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCharLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a char value that represents + * null for the Key set. + * @param noEntryValue a long value that represents + * null for the Value set. + */ + public TCharLongHashMap( int initialCapacity, float loadFactor, + char noEntryKey, long noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TCharLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a char array containing the keys for the matching values. + * @param values a long array containing the values. + */ + public TCharLongHashMap( char[] keys, long[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TCharLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TCharLongMap that will be duplicated. + */ + public TCharLongHashMap( TCharLongMap map ) { + super( map.size() ); + if ( map instanceof TCharLongHashMap ) { + TCharLongHashMap hashmap = ( TCharLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + long oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public long put( char key, long value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( char key, long value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private long doPut( char key, long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().charValue(), entry.getValue().longValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharLongMap map ) { + ensureCapacity( map.size() ); + TCharLongIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public long get( char key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public long remove( char key ) { + long prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public char[] keys() { + char[] keys = new char[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public char[] keys( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + byte[] states = _states; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TCharLongIterator iterator() { + return new TCharLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TLongProcedure procedure ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TCharLongProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TCharLongProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + long[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( char key ) { + return adjustValue( key, ( long ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( char key, long amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( char key, long adjust_amount, long put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TCharSet { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharLongKeyHashIterator( TCharLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharLongHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharLongHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharLongHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharLongMap + *

+ * {@inheritDoc} + */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return no_entry_value != TCharLongHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharLongHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharLongHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharLongHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharLongHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TCharSet)) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TCharProcedure() { + private boolean first = true; + + + public boolean execute( char key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TCharLongValueHashIterator( TCharLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TCharLongHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TCharLongHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TCharLongHashMap.this.values( dest ); + } + + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + char[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TCharLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TCharLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TCharLongHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TCharLongKeyHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharLongKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TCharLongValueHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharLongValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TCharLongHashIterator extends THashPrimitiveIterator implements TCharLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TCharLongHashMap we will be iterating over. + */ + TCharLongHashIterator( TCharLongHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharLongMap ) ) { + return false; + } + TCharLongMap that = ( TCharLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + long[] values = _values; + byte[] states = _states; + long this_no_entry_value = getNoEntryValue(); + long that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + char key = _set[i]; + long that_value = that.get( key ); + long this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TCharLongProcedure() { + private boolean first = true; + public boolean execute( char key, long value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + long val = in.readLong(); + put(key, val); + } + } +} // TCharLongHashMap diff --git a/src/gnu/trove/map/hash/TCharObjectHashMap.java b/src/gnu/trove/map/hash/TCharObjectHashMap.java new file mode 100644 index 0000000..e9e533f --- /dev/null +++ b/src/gnu/trove/map/hash/TCharObjectHashMap.java @@ -0,0 +1,1037 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import gnu.trove.TCharCollection; +import gnu.trove.function.TObjectFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TCharObjectIterator; +import gnu.trove.map.TCharObjectMap; +import gnu.trove.procedure.TCharObjectProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.set.TCharSet; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for char keys and Object values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TCharObjectHashMap extends TCharHash implements + TCharObjectMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TCharObjectProcedure PUT_ALL_PROC = new TCharObjectProcedure() { + public boolean execute( char key, V value) { + put( key, value ); + return true; + } + }; + + /** the values of the map */ + protected transient V[] _values; + + /** the value that represents null in the key set. */ + protected char no_entry_key; + + + /** + * Creates a new TCharObjectHashMap instance with the default + * capacity and load factor. + */ + public TCharObjectHashMap() { + super(); + } + + + /** + * Creates a new TCharObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharObjectHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TCharObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharObjectHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_key = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TCharObjectHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryKey the value used to represent null in the key set. + */ + public TCharObjectHashMap( int initialCapacity, float loadFactor, char noEntryKey ) { + super( initialCapacity, loadFactor ); + no_entry_key = noEntryKey; + } + + + /** + * Creates a new TCharObjectHashMap that contains the entries + * in the map passed to it. + * + * @param map the TCharObjectMap to be copied. + */ + public TCharObjectHashMap( TCharObjectMap map ) { + this( map.size(), 0.5f, map.getNoEntryKey() ); + putAll( map ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = ( V[] ) new Object[capacity]; + return capacity; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + V oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = (V[]) new Object[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey(o); + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public char getNoEntryKey() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( Object val ) { + byte[] states = _states; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && null == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && + ( val == vals[i] || val.equals( vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + /** {@inheritDoc} */ + public V get( char key ) { + int index = index( key ); + return index < 0 ? null : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public V put( char key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public V putIfAbsent( char key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + @SuppressWarnings({}) + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public V remove( char key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharObjectMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _states, 0, _states.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + // Views + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public char[] keys() { + char[] keys = new char[size()]; + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public char[] keys( char[] dest ) { + if ( dest.length < _size ) { + dest = new char[_size]; + } + + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = k[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public Collection valueCollection() { + return new ValueView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public Object[] values() { + Object[] vals = new Object[size()]; + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public V[] values( V[] dest ) { + if ( dest.length < _size ) { + dest = ( V[] ) java.lang.reflect.Array.newInstance( + dest.getClass().getComponentType(), _size); + } + + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = ( V ) v[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public TCharObjectIterator iterator() { + return new TCharObjectHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TObjectProcedure procedure ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean forEachEntry( TCharObjectProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (states[i] == FULL && ! procedure.execute(keys[i],values[i])) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainEntries( TCharObjectProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public void transformValues( TObjectFunction function ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** {@inheritDoc} */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharObjectMap ) ) { + return false; + } + TCharObjectMap that = ( TCharObjectMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TCharObjectIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + char key = iter.key(); + Object value = iter.value(); + if ( value == null ) { + if ( !( that.get( key ) == null && that.containsKey( key ) ) ) { + return false; + } + } else { + if ( !value.equals( that.get( key ) ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + V[] values = _values; + byte[] states = _states; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + ( values[i] == null ? 0 : values[i].hashCode() ); + } + } + return hashcode; + } + + + class KeyView implements TCharSet { + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _size == 0; + } + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharObjectHashMap.this.containsKey( entry ); + } + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharHashIterator( TCharObjectHashMap.this ); + } + + /** {@inheritDoc} */ + public char[] toArray() { + return keys(); + } + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return keys( dest ); + } + + /** {@inheritDoc} */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return null != TCharObjectHashMap.this.remove( entry ); + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( ! TCharObjectHashMap.this.containsKey( + ( ( Character ) element ).charValue() ) ) { + + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + if ( collection == this ) { + return true; + } + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharObjectHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharObjectHashMap.this.containsKey( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + //noinspection SuspiciousMethodCalls + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TCharObjectHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharObjectHashMap.this.forEachKey( procedure ); + } + + /** {@inheritDoc) */ + public boolean equals( Object other ) { + if (! ( other instanceof TCharSet ) ) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( first ) first = false; + else buf.append( "," ); + buf.append( _set[i] ); + } + } + return buf.toString(); + } + + + class TCharHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** the collection on which the iterator operates */ + private final TCharHash _hash; + + /** {@inheritDoc} */ + public TCharHashIterator( TCharHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({}) + public Iterator iterator() { + return new TCharObjectValueHashIterator( TCharObjectHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + public boolean removeElement( V value ) { + V[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + if ( value == values[i] || + ( null != values[i] && values[i].equals( value ) ) ) { + removeAt( i ); + return true; + } + } + } + return false; + } + + class TCharObjectValueHashIterator extends THashPrimitiveIterator + implements Iterator { + + @SuppressWarnings("rawtypes") + protected final TCharObjectHashMap _map; + + @SuppressWarnings("rawtypes") + public TCharObjectValueHashIterator( TCharObjectHashMap map ) { + super( map ); + _map = map; + } + + @SuppressWarnings("unchecked") + protected V objectAtIndex( int index ) { + byte[] states = _states; + Object value = _map._values[index]; + if ( states[index] != FULL ) { + return null; + } + return ( V ) value; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public V next() { + moveToNextIndex(); + return ( V ) _map._values[_index]; + } + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TCharObjectHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TCharObjectHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TCharObjectHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + @SuppressWarnings("hiding") + class TCharObjectHashIterator extends THashPrimitiveIterator + implements TCharObjectIterator { + + /** the collection being iterated over */ + private final TCharObjectHashMap _map; + + /** + * Creates an iterator over the specified map + * + * @param map map to iterate over. + */ + public TCharObjectHashIterator( TCharObjectHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _map._set[_index]; + } + + /** {@inheritDoc} */ + public V value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public V setValue( V val ) { + V old = value(); + _map._values[_index] = val; + return old; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeChar( no_entry_key ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readChar(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + V val = (V) in.readObject(); + put(key, val); + } + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TCharObjectProcedure() { + private boolean first = true; + public boolean execute(char key, Object value) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } +} // TCharObjectHashMap diff --git a/src/gnu/trove/map/hash/TCharShortHashMap.java b/src/gnu/trove/map/hash/TCharShortHashMap.java new file mode 100644 index 0000000..375d1bc --- /dev/null +++ b/src/gnu/trove/map/hash/TCharShortHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.TShortCollection; +import gnu.trove.function.TShortFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCharShortHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TCharShortIterator; +import gnu.trove.iterator.TShortIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TCharShortMap; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TCharShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TCharSet; + +/** + * An open addressed Map implementation for char keys and short values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TCharShortHashMap extends TCharShortHash implements TCharShortMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient short[] _values; + + + /** + * Creates a new TCharShortHashMap instance with the default + * capacity and load factor. + */ + public TCharShortHashMap() { + super(); + } + + + /** + * Creates a new TCharShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharShortHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TCharShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCharShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCharShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a char value that represents + * null for the Key set. + * @param noEntryValue a short value that represents + * null for the Value set. + */ + public TCharShortHashMap( int initialCapacity, float loadFactor, + char noEntryKey, short noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TCharShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a char array containing the keys for the matching values. + * @param values a short array containing the values. + */ + public TCharShortHashMap( char[] keys, short[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TCharShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TCharShortMap that will be duplicated. + */ + public TCharShortHashMap( TCharShortMap map ) { + super( map.size() ); + if ( map instanceof TCharShortHashMap ) { + TCharShortHashMap hashmap = ( TCharShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldKeys[] = _set; + short oldVals[] = _values; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _values = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public short put( char key, short value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( char key, short value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private short doPut( char key, short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().charValue(), entry.getValue().shortValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TCharShortMap map ) { + ensureCapacity( map.size() ); + TCharShortIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public short get( char key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public short remove( char key ) { + short prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TCharSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public char[] keys() { + char[] keys = new char[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + char[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public char[] keys( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + byte[] states = _states; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( char key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TCharShortIterator iterator() { + return new TCharShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TCharProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TShortProcedure procedure ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TCharShortProcedure procedure ) { + byte[] states = _states; + char[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TCharShortProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + char[] keys = _set; + short[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( char key ) { + return adjustValue( key, ( short ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( char key, short amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( char key, short adjust_amount, short put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TCharSet { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharShortKeyHashIterator( TCharShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TCharShortHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TCharShortHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TCharShortHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharShortMap + *

+ * {@inheritDoc} + */ + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + return no_entry_value != TCharShortHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TCharShortHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharShortHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TCharShortHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TCharShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TCharShortHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TCharSet)) { + return false; + } + final TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TCharProcedure() { + private boolean first = true; + + + public boolean execute( char key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TCharShortValueHashIterator( TCharShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TCharShortHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TCharShortHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TCharShortHashMap.this.values( dest ); + } + + + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + char[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TCharShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TCharShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TCharShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TCharShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TCharShortHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TCharShortKeyHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharShortKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TCharShortValueHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TCharShortValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TCharShortHashIterator extends THashPrimitiveIterator implements TCharShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TCharShortHashMap we will be iterating over. + */ + TCharShortHashIterator( TCharShortHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public char key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TCharShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharShortMap ) ) { + return false; + } + TCharShortMap that = ( TCharShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + short[] values = _values; + byte[] states = _states; + short this_no_entry_value = getNoEntryValue(); + short that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + char key = _set[i]; + short that_value = that.get( key ); + short this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TCharShortProcedure() { + private boolean first = true; + public boolean execute( char key, short value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + char key = in.readChar(); + short val = in.readShort(); + put(key, val); + } + } +} // TCharShortHashMap diff --git a/src/gnu/trove/map/hash/TCustomHashMap.java b/src/gnu/trove/map/hash/TCustomHashMap.java new file mode 100644 index 0000000..983fc31 --- /dev/null +++ b/src/gnu/trove/map/hash/TCustomHashMap.java @@ -0,0 +1,912 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.function.TObjectFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TMap; +import gnu.trove.procedure.TObjectObjectProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.strategy.HashingStrategy; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + + +/** + * An implementation of the Map interface which uses an open addressed + * hash table to store its contents. + * + * @author Rob Eden + */ +public class TCustomHashMap extends TCustomObjectHash + implements TMap, Externalizable { + + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient V[] _values; + + /** FOR EXTERNALIZATION ONLY!!! */ + public TCustomHashMap() { + super(); + } + + + /** + * Creates a new TCustomHashMap instance with the default + * capacity and load factor. + */ + public TCustomHashMap( HashingStrategy strategy ) { + super( strategy ); + } + + + /** + * Creates a new TCustomHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCustomHashMap( HashingStrategy strategy, int initialCapacity ) { + super( strategy, initialCapacity ); + } + + + /** + * Creates a new TCustomHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCustomHashMap( HashingStrategy strategy, int initialCapacity, + float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + } + + + /** + * Creates a new TCustomHashMap instance which contains the + * key/value pairs in map. + * + * @param map a Map value + */ + public TCustomHashMap( HashingStrategy strategy, + Map map ) { + + this( strategy, map.size() ); + putAll( map ); + } + + + /** + * Creates a new TCustomHashMap instance which contains the + * key/value pairs in map. + * + * @param map a Map value + */ + public TCustomHashMap( HashingStrategy strategy, + TCustomHashMap map ) { + + this( strategy, map.size() ); + putAll( map ); + } + + + /** + * initialize the value array of the map. + * + * @param initialCapacity an int value + * @return an int value + */ + @SuppressWarnings("unchecked") + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + //noinspection unchecked + _values = (V[]) new Object[capacity]; + return capacity; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or {@code null} if none was found. + */ + public V put( K key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or {@code null} if none was found. + */ + public V putIfAbsent( K key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) { + return _values[-index - 1]; + } + return doPut(value, index ); + } + + + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index - 1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings({"unchecked"}) + public boolean equals( Object other ) { + if ( !( other instanceof Map ) ) { + return false; + } + Map that = (Map) other; + if ( that.size() != this.size() ) { + return false; + } + return forEachEntry( new EqProcedure( that ) ); + } + + + public int hashCode() { + HashProcedure p = new HashProcedure(); + forEachEntry( p ); + return p.getHashCode(); + } + + + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TObjectObjectProcedure() { + private boolean first = true; + + + public boolean execute( K key, V value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + buf.append( "=" ); + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + private final class HashProcedure implements TObjectObjectProcedure { + private int h = 0; + + public int getHashCode() { + return h; + } + + public final boolean execute( K key, V value ) { + h += HashFunctions.hash( key ) ^ ( value == null ? 0 : value.hashCode() ); + return true; + } + } + + private static final class EqProcedure implements TObjectObjectProcedure { + private final Map _otherMap; + + + EqProcedure( Map otherMap ) { + _otherMap = otherMap; + } + + + public final boolean execute( K key, V value ) { + // Check to make sure the key is there. This avoids problems that come up with + // null values. Since it is only caused in that cause, only do this when the + // value is null (to avoid extra work). + if ( value == null && !_otherMap.containsKey( key ) ) { + return false; + } + + V oValue = _otherMap.get( key ); + return oValue == value || ( oValue != null && oValue.equals( value ) ); + } + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TObjectProcedure procedure ) { + V[] values = _values; + Object[] set = _set; + for ( int i = values.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && !procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TObjectObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectObjectProcedure procedure ) { + Object[] keys = _set; + V[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && !procedure.execute( (K) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings({"unchecked"}) + public boolean retainEntries( TObjectObjectProcedure procedure ) { + boolean modified = false; + Object[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && !procedure.execute( (K) keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues( TObjectFunction function ) { + V[] values = _values; + Object[] set = _set; + for ( int i = values.length; i-- > 0; ) { + if ( set[i] != FREE && set[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + int oldSize = size(); + Object oldKeys[] = _set; + V oldVals[] = _values; + + _set = new Object[ newCapacity ]; + Arrays.fill( _set, FREE ); + _values = ( V[] ) new Object[ newCapacity ]; + + // Process entries from the old array, skipping free and removed slots. Put the + // values into the appropriate place in the new array. + for ( int i = oldCapacity; i-- > 0; ) { + Object o = oldKeys[ i ]; + if ( o == FREE || o == REMOVED ) continue; + + int index = insertKey( ( K ) o ); + if ( index < 0 ) { + throwObjectContractViolation( _set[ ( -index - 1 ) ], o, size(), oldSize, oldKeys); + } + _values[ index ] = oldVals[ i ]; + } + } + + + /** + * retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + @SuppressWarnings({"unchecked"}) + public V get( Object key ) { + int index = index( key ); + if ( index < 0 || ! strategy.equals( ( K ) _set[index], ( K ) key ) ) { + return null; + } + return _values[index]; + } + + + /** Empties the map. */ + public void clear() { + if ( size() == 0 ) { + return; // optimization + } + + super.clear(); + + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return an Object value + */ + @SuppressWarnings({}) + public V remove( Object key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * removes the mapping at index from the map. + * + * @param index an int value + */ + public void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** + * Returns a view on the values of the map. + * + * @return a Collection value + */ + public Collection values() { + return new ValueView(); + } + + + /** + * returns a Set view on the keys of the map. + * + * @return a Set value + */ + public Set keySet() { + return new KeyView(); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new EntryView(); + } + + + /** + * checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + @SuppressWarnings("unchecked") + public boolean containsValue( Object val ) { + Object[] set = _set; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && + val == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && + ( val == vals[i] || strategy.equals( ( K ) val, ( K ) vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + /** + * checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** + * copies the key/value mappings in map into this map. + * + * @param map a Map value + */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof TCustomHashMap + for ( Map.Entry e : map.entrySet() ) { + put( e.getKey(), e.getValue() ); + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TCustomHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + + @SuppressWarnings("unchecked") + public boolean removeElement( V value ) { + Object[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && + value == values[i] || + ( null != values[i] && strategy.equals( ( K ) values[i], ( K ) value ) ) ) { + + removeAt( i ); + return true; + } + } + + return false; + } + } + + /** a view onto the entries of the map. */ + protected class EntryView extends MapBackedView> { + + @SuppressWarnings("rawtypes") + private final class EntryIterator extends TObjectHashIterator { + + @SuppressWarnings("unchecked") + EntryIterator( TCustomHashMap map ) { + super( map ); + } + + + @SuppressWarnings({"unchecked"}) + public Entry objectAtIndex( final int index ) { + return new Entry( (K) _set[index], _values[index], index ); + } + } + + + @SuppressWarnings({"unchecked"}) + public Iterator> iterator() { + return new EntryIterator( TCustomHashMap.this ); + } + + + @SuppressWarnings("unchecked") + public boolean removeElement( Map.Entry entry ) { + // have to effectively reimplement Map.remove here + // because we need to return true/false depending on + // whether the removal took place. Since the Entry's + // value can be null, this means that we can't rely + // on the value of the object returned by Map.remove() + // to determine whether a deletion actually happened. + // + // Note also that the deletion is only legal if + // both the key and the value match. + Object val; + int index; + + K key = keyForEntry( entry ); + index = index( key ); + if ( index >= 0 ) { + val = valueForEntry( entry ); + if ( val == _values[index] || + ( null != val && strategy.equals( ( K ) val, ( K ) _values[index] ) ) ) { + removeAt( index ); // clear key,state; adjust size + return true; + } + } + return false; + } + + + @SuppressWarnings("unchecked") + public boolean containsElement( Map.Entry entry ) { + Object val = get( keyForEntry( entry ) ); + Object entryValue = entry.getValue(); + return entryValue == val || + ( null != val && strategy.equals( ( K ) val, ( K ) entryValue ) ); + } + + + protected V valueForEntry( Map.Entry entry ) { + return entry.getValue(); + } + + + protected K keyForEntry( Map.Entry entry ) { + return entry.getKey(); + } + } + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + + public abstract boolean removeElement( E key ); + + + public abstract boolean containsElement( E key ); + + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + +// public boolean containsAll( Collection collection ) { +// for ( Object element : collection ) { +// if ( !contains( element ) ) { +// return false; +// } +// } +// return true; +// } + + + public void clear() { + TCustomHashMap.this.clear(); + } + + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + + public int size() { + return TCustomHashMap.this.size(); + } + + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + + public boolean isEmpty() { + return TCustomHashMap.this.isEmpty(); + } + + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + + public String toString() { + Iterator i = iterator(); + if ( !i.hasNext() ) return "{}"; + + StringBuilder sb = new StringBuilder(); + sb.append( '{' ); + for (; ; ) { + E e = i.next(); + sb.append( e == this ? "(this Collection)" : e ); + if ( !i.hasNext() ) return sb.append( '}' ).toString(); + sb.append( ", " ); + } + } + } + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TCustomHashMap.this ); + } + + + public boolean removeElement( K key ) { + return null != TCustomHashMap.this.remove( key ); + } + + + public boolean containsElement( K key ) { + return TCustomHashMap.this.contains( key ); + } + } + + final class Entry implements Map.Entry { + + private K key; + private V val; + private final int index; + + + Entry( final K key, V value, final int index ) { + this.key = key; + this.val = value; + this.index = index; + } + + + public K getKey() { + return key; + } + + + public V getValue() { + return val; + } + + + public V setValue( V o ) { + if ( _values[index] != val ) { + throw new ConcurrentModificationException(); + } + // need to return previous value + V retval = val; + // update this entry's value, in case setValue is called again + _values[index] = o; + val = o; + return retval; + } + + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public boolean equals( Object o ) { + if ( o instanceof Map.Entry ) { + Map.Entry e1 = this; + Map.Entry e2 = (Map.Entry) o; + return ( e1.getKey() == null ? e2.getKey() == null : + strategy.equals( e1.getKey(), ( K ) e2.getKey() ) ) && + ( e1.getValue() == null ? e2.getValue() == null : + e1.getValue().equals( e2.getValue() ) ); + } + return false; + } + + + public int hashCode() { + return ( getKey() == null ? 0 : getKey().hashCode() ) ^ ( getValue() == null ? 0 : getValue().hashCode() ); + } + + + @Override + public String toString() { + return key + "=" + val; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 1 ); + + // NOTE: Super was not written in version 0 + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + byte version = in.readByte(); + + // NOTE: super was not written in version 0 + if ( version != 0 ) { + super.readExternal( in ); + } + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while ( size-- > 0 ) { + //noinspection unchecked + K key = (K) in.readObject(); + //noinspection unchecked + V val = (V) in.readObject(); + put( key, val ); + } + } +} // TCustomHashMap diff --git a/src/gnu/trove/map/hash/TDoubleByteHashMap.java b/src/gnu/trove/map/hash/TDoubleByteHashMap.java new file mode 100644 index 0000000..d41086d --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleByteHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TByteFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleByteHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TDoubleByteIterator; +import gnu.trove.iterator.TDoubleIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TDoubleByteMap; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TDoubleByteProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TDoubleSet; + +/** + * An open addressed Map implementation for double keys and byte values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TDoubleByteHashMap extends TDoubleByteHash implements TDoubleByteMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient byte[] _values; + + + /** + * Creates a new TDoubleByteHashMap instance with the default + * capacity and load factor. + */ + public TDoubleByteHashMap() { + super(); + } + + + /** + * Creates a new TDoubleByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleByteHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TDoubleByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TDoubleByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a double value that represents + * null for the Key set. + * @param noEntryValue a byte value that represents + * null for the Value set. + */ + public TDoubleByteHashMap( int initialCapacity, float loadFactor, + double noEntryKey, byte noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TDoubleByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a double array containing the keys for the matching values. + * @param values a byte array containing the values. + */ + public TDoubleByteHashMap( double[] keys, byte[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TDoubleByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TDoubleByteMap that will be duplicated. + */ + public TDoubleByteHashMap( TDoubleByteMap map ) { + super( map.size() ); + if ( map instanceof TDoubleByteHashMap ) { + TDoubleByteHashMap hashmap = ( TDoubleByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + byte oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public byte put( double key, byte value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( double key, byte value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private byte doPut( double key, byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().doubleValue(), entry.getValue().byteValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleByteMap map ) { + ensureCapacity( map.size() ); + TDoubleByteIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public byte get( double key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public byte remove( double key ) { + byte prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + byte[] states = _states; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TDoubleByteIterator iterator() { + return new TDoubleByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TByteProcedure procedure ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleByteProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleByteProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + byte[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( double key ) { + return adjustValue( key, ( byte ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( double key, byte amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( double key, byte adjust_amount, byte put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleByteKeyHashIterator( TDoubleByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleByteHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleByteHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleByteHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleByteMap + *

+ * {@inheritDoc} + */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return no_entry_value != TDoubleByteHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleByteHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleByteHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleByteHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleByteHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TDoubleSet)) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TDoubleProcedure() { + private boolean first = true; + + + public boolean execute( double key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TDoubleByteValueHashIterator( TDoubleByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TDoubleByteHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TDoubleByteHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TDoubleByteHashMap.this.values( dest ); + } + + + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + double[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TDoubleByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TDoubleByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TDoubleByteHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TDoubleByteKeyHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleByteKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TDoubleByteValueHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleByteValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TDoubleByteHashIterator extends THashPrimitiveIterator implements TDoubleByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TDoubleByteHashMap we will be iterating over. + */ + TDoubleByteHashIterator( TDoubleByteHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleByteMap ) ) { + return false; + } + TDoubleByteMap that = ( TDoubleByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + byte[] values = _values; + byte[] states = _states; + byte this_no_entry_value = getNoEntryValue(); + byte that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + double key = _set[i]; + byte that_value = that.get( key ); + byte this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TDoubleByteProcedure() { + private boolean first = true; + public boolean execute( double key, byte value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + byte val = in.readByte(); + put(key, val); + } + } +} // TDoubleByteHashMap diff --git a/src/gnu/trove/map/hash/TDoubleCharHashMap.java b/src/gnu/trove/map/hash/TDoubleCharHashMap.java new file mode 100644 index 0000000..89db583 --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleCharHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TCharFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleCharHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TDoubleCharIterator; +import gnu.trove.iterator.TDoubleIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TDoubleCharMap; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TDoubleCharProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TDoubleSet; + +/** + * An open addressed Map implementation for double keys and char values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TDoubleCharHashMap extends TDoubleCharHash implements TDoubleCharMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient char[] _values; + + + /** + * Creates a new TDoubleCharHashMap instance with the default + * capacity and load factor. + */ + public TDoubleCharHashMap() { + super(); + } + + + /** + * Creates a new TDoubleCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleCharHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TDoubleCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TDoubleCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a double value that represents + * null for the Key set. + * @param noEntryValue a char value that represents + * null for the Value set. + */ + public TDoubleCharHashMap( int initialCapacity, float loadFactor, + double noEntryKey, char noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TDoubleCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a double array containing the keys for the matching values. + * @param values a char array containing the values. + */ + public TDoubleCharHashMap( double[] keys, char[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TDoubleCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TDoubleCharMap that will be duplicated. + */ + public TDoubleCharHashMap( TDoubleCharMap map ) { + super( map.size() ); + if ( map instanceof TDoubleCharHashMap ) { + TDoubleCharHashMap hashmap = ( TDoubleCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + char oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public char put( double key, char value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( double key, char value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private char doPut( double key, char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().doubleValue(), entry.getValue().charValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleCharMap map ) { + ensureCapacity( map.size() ); + TDoubleCharIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public char get( double key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public char remove( double key ) { + char prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + byte[] states = _states; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TDoubleCharIterator iterator() { + return new TDoubleCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TCharProcedure procedure ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleCharProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleCharProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + char[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( double key ) { + return adjustValue( key, ( char ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( double key, char amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( double key, char adjust_amount, char put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleCharKeyHashIterator( TDoubleCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleCharHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleCharHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleCharHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleCharMap + *

+ * {@inheritDoc} + */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return no_entry_value != TDoubleCharHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleCharHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleCharHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleCharHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleCharHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TDoubleSet)) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TDoubleProcedure() { + private boolean first = true; + + + public boolean execute( double key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TDoubleCharValueHashIterator( TDoubleCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TDoubleCharHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TDoubleCharHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TDoubleCharHashMap.this.values( dest ); + } + + + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + double[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TDoubleCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TDoubleCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TDoubleCharHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TDoubleCharKeyHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleCharKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TDoubleCharValueHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleCharValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TDoubleCharHashIterator extends THashPrimitiveIterator implements TDoubleCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TDoubleCharHashMap we will be iterating over. + */ + TDoubleCharHashIterator( TDoubleCharHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleCharMap ) ) { + return false; + } + TDoubleCharMap that = ( TDoubleCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + char[] values = _values; + byte[] states = _states; + char this_no_entry_value = getNoEntryValue(); + char that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + double key = _set[i]; + char that_value = that.get( key ); + char this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TDoubleCharProcedure() { + private boolean first = true; + public boolean execute( double key, char value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + char val = in.readChar(); + put(key, val); + } + } +} // TDoubleCharHashMap diff --git a/src/gnu/trove/map/hash/TDoubleDoubleHashMap.java b/src/gnu/trove/map/hash/TDoubleDoubleHashMap.java new file mode 100644 index 0000000..69c6a35 --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleDoubleHashMap.java @@ -0,0 +1,1307 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleDoubleHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TDoubleDoubleIterator; +import gnu.trove.iterator.TDoubleIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TDoubleDoubleMap; +import gnu.trove.procedure.TDoubleDoubleProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.set.TDoubleSet; + +/** + * An open addressed Map implementation for double keys and double values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TDoubleDoubleHashMap extends TDoubleDoubleHash implements TDoubleDoubleMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient double[] _values; + + + /** + * Creates a new TDoubleDoubleHashMap instance with the default + * capacity and load factor. + */ + public TDoubleDoubleHashMap() { + super(); + } + + + /** + * Creates a new TDoubleDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TDoubleDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TDoubleDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a double value that represents + * null for the Key set. + * @param noEntryValue a double value that represents + * null for the Value set. + */ + public TDoubleDoubleHashMap( int initialCapacity, float loadFactor, + double noEntryKey, double noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TDoubleDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a double array containing the keys for the matching values. + * @param values a double array containing the values. + */ + public TDoubleDoubleHashMap( double[] keys, double[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TDoubleDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TDoubleDoubleMap that will be duplicated. + */ + public TDoubleDoubleHashMap( TDoubleDoubleMap map ) { + super( map.size() ); + if ( map instanceof TDoubleDoubleHashMap ) { + TDoubleDoubleHashMap hashmap = ( TDoubleDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + double oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public double put( double key, double value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( double key, double value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private double doPut( double key, double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().doubleValue(), entry.getValue().doubleValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleDoubleMap map ) { + ensureCapacity( map.size() ); + TDoubleDoubleIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public double get( double key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public double remove( double key ) { + double prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + byte[] states = _states; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TDoubleDoubleIterator iterator() { + return new TDoubleDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleDoubleProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleDoubleProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + double[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( double key ) { + return adjustValue( key, ( double ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( double key, double amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( double key, double adjust_amount, double put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleDoubleKeyHashIterator( TDoubleDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleDoubleHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleDoubleHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleDoubleHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleDoubleMap + *

+ * {@inheritDoc} + */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return no_entry_value != TDoubleDoubleHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleDoubleHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleDoubleHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleDoubleHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleDoubleHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TDoubleSet)) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TDoubleProcedure() { + private boolean first = true; + + + public boolean execute( double key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleDoubleValueHashIterator( TDoubleDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleDoubleHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleDoubleHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleDoubleHashMap.this.values( dest ); + } + + + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + double[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleDoubleHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TDoubleDoubleKeyHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleDoubleKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TDoubleDoubleValueHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleDoubleValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TDoubleDoubleHashIterator extends THashPrimitiveIterator implements TDoubleDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TDoubleDoubleHashMap we will be iterating over. + */ + TDoubleDoubleHashIterator( TDoubleDoubleHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleDoubleMap ) ) { + return false; + } + TDoubleDoubleMap that = ( TDoubleDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + double[] values = _values; + byte[] states = _states; + double this_no_entry_value = getNoEntryValue(); + double that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + double key = _set[i]; + double that_value = that.get( key ); + double this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TDoubleDoubleProcedure() { + private boolean first = true; + public boolean execute( double key, double value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + double val = in.readDouble(); + put(key, val); + } + } +} // TDoubleDoubleHashMap diff --git a/src/gnu/trove/map/hash/TDoubleFloatHashMap.java b/src/gnu/trove/map/hash/TDoubleFloatHashMap.java new file mode 100644 index 0000000..c6dad34 --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleFloatHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.TFloatCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleFloatHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TDoubleFloatIterator; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TFloatIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TDoubleFloatMap; +import gnu.trove.procedure.TDoubleFloatProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TDoubleSet; + +/** + * An open addressed Map implementation for double keys and float values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TDoubleFloatHashMap extends TDoubleFloatHash implements TDoubleFloatMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient float[] _values; + + + /** + * Creates a new TDoubleFloatHashMap instance with the default + * capacity and load factor. + */ + public TDoubleFloatHashMap() { + super(); + } + + + /** + * Creates a new TDoubleFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TDoubleFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TDoubleFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a double value that represents + * null for the Key set. + * @param noEntryValue a float value that represents + * null for the Value set. + */ + public TDoubleFloatHashMap( int initialCapacity, float loadFactor, + double noEntryKey, float noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TDoubleFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a double array containing the keys for the matching values. + * @param values a float array containing the values. + */ + public TDoubleFloatHashMap( double[] keys, float[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TDoubleFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TDoubleFloatMap that will be duplicated. + */ + public TDoubleFloatHashMap( TDoubleFloatMap map ) { + super( map.size() ); + if ( map instanceof TDoubleFloatHashMap ) { + TDoubleFloatHashMap hashmap = ( TDoubleFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + float oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public float put( double key, float value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( double key, float value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private float doPut( double key, float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().doubleValue(), entry.getValue().floatValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleFloatMap map ) { + ensureCapacity( map.size() ); + TDoubleFloatIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public float get( double key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public float remove( double key ) { + float prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + byte[] states = _states; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TDoubleFloatIterator iterator() { + return new TDoubleFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TFloatProcedure procedure ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleFloatProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleFloatProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + float[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( double key ) { + return adjustValue( key, ( float ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( double key, float amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( double key, float adjust_amount, float put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleFloatKeyHashIterator( TDoubleFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleFloatHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleFloatHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleFloatHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleFloatMap + *

+ * {@inheritDoc} + */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return no_entry_value != TDoubleFloatHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleFloatHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleFloatHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleFloatHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleFloatHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TDoubleSet)) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TDoubleProcedure() { + private boolean first = true; + + + public boolean execute( double key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TDoubleFloatValueHashIterator( TDoubleFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TDoubleFloatHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TDoubleFloatHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TDoubleFloatHashMap.this.values( dest ); + } + + + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + double[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TDoubleFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TDoubleFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TDoubleFloatHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TDoubleFloatKeyHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleFloatKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TDoubleFloatValueHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleFloatValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TDoubleFloatHashIterator extends THashPrimitiveIterator implements TDoubleFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TDoubleFloatHashMap we will be iterating over. + */ + TDoubleFloatHashIterator( TDoubleFloatHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleFloatMap ) ) { + return false; + } + TDoubleFloatMap that = ( TDoubleFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + float[] values = _values; + byte[] states = _states; + float this_no_entry_value = getNoEntryValue(); + float that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + double key = _set[i]; + float that_value = that.get( key ); + float this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TDoubleFloatProcedure() { + private boolean first = true; + public boolean execute( double key, float value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + float val = in.readFloat(); + put(key, val); + } + } +} // TDoubleFloatHashMap diff --git a/src/gnu/trove/map/hash/TDoubleIntHashMap.java b/src/gnu/trove/map/hash/TDoubleIntHashMap.java new file mode 100644 index 0000000..35e16bc --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleIntHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.TIntCollection; +import gnu.trove.function.TIntFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleIntHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TDoubleIntIterator; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TIntIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TDoubleIntMap; +import gnu.trove.procedure.TDoubleIntProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TDoubleSet; + +/** + * An open addressed Map implementation for double keys and int values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TDoubleIntHashMap extends TDoubleIntHash implements TDoubleIntMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient int[] _values; + + + /** + * Creates a new TDoubleIntHashMap instance with the default + * capacity and load factor. + */ + public TDoubleIntHashMap() { + super(); + } + + + /** + * Creates a new TDoubleIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleIntHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TDoubleIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TDoubleIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a double value that represents + * null for the Key set. + * @param noEntryValue a int value that represents + * null for the Value set. + */ + public TDoubleIntHashMap( int initialCapacity, float loadFactor, + double noEntryKey, int noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TDoubleIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a double array containing the keys for the matching values. + * @param values a int array containing the values. + */ + public TDoubleIntHashMap( double[] keys, int[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TDoubleIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TDoubleIntMap that will be duplicated. + */ + public TDoubleIntHashMap( TDoubleIntMap map ) { + super( map.size() ); + if ( map instanceof TDoubleIntHashMap ) { + TDoubleIntHashMap hashmap = ( TDoubleIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + int oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public int put( double key, int value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( double key, int value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private int doPut( double key, int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().doubleValue(), entry.getValue().intValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleIntMap map ) { + ensureCapacity( map.size() ); + TDoubleIntIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public int get( double key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public int remove( double key ) { + int prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + byte[] states = _states; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TDoubleIntIterator iterator() { + return new TDoubleIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TIntProcedure procedure ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleIntProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleIntProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + int[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( double key ) { + return adjustValue( key, ( int ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( double key, int amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( double key, int adjust_amount, int put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleIntKeyHashIterator( TDoubleIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleIntHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleIntHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleIntHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleIntMap + *

+ * {@inheritDoc} + */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return no_entry_value != TDoubleIntHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleIntHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleIntHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleIntHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleIntHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TDoubleSet)) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TDoubleProcedure() { + private boolean first = true; + + + public boolean execute( double key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TDoubleIntValueHashIterator( TDoubleIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TDoubleIntHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TDoubleIntHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TDoubleIntHashMap.this.values( dest ); + } + + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + double[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TDoubleIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TDoubleIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TDoubleIntHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TDoubleIntKeyHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleIntKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TDoubleIntValueHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleIntValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TDoubleIntHashIterator extends THashPrimitiveIterator implements TDoubleIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TDoubleIntHashMap we will be iterating over. + */ + TDoubleIntHashIterator( TDoubleIntHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleIntMap ) ) { + return false; + } + TDoubleIntMap that = ( TDoubleIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + int[] values = _values; + byte[] states = _states; + int this_no_entry_value = getNoEntryValue(); + int that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + double key = _set[i]; + int that_value = that.get( key ); + int this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TDoubleIntProcedure() { + private boolean first = true; + public boolean execute( double key, int value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + int val = in.readInt(); + put(key, val); + } + } +} // TDoubleIntHashMap diff --git a/src/gnu/trove/map/hash/TDoubleLongHashMap.java b/src/gnu/trove/map/hash/TDoubleLongHashMap.java new file mode 100644 index 0000000..e5f07e7 --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleLongHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.TLongCollection; +import gnu.trove.function.TLongFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleLongHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TDoubleLongIterator; +import gnu.trove.iterator.TLongIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TDoubleLongMap; +import gnu.trove.procedure.TDoubleLongProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TDoubleSet; + +/** + * An open addressed Map implementation for double keys and long values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TDoubleLongHashMap extends TDoubleLongHash implements TDoubleLongMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient long[] _values; + + + /** + * Creates a new TDoubleLongHashMap instance with the default + * capacity and load factor. + */ + public TDoubleLongHashMap() { + super(); + } + + + /** + * Creates a new TDoubleLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleLongHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TDoubleLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TDoubleLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a double value that represents + * null for the Key set. + * @param noEntryValue a long value that represents + * null for the Value set. + */ + public TDoubleLongHashMap( int initialCapacity, float loadFactor, + double noEntryKey, long noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TDoubleLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a double array containing the keys for the matching values. + * @param values a long array containing the values. + */ + public TDoubleLongHashMap( double[] keys, long[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TDoubleLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TDoubleLongMap that will be duplicated. + */ + public TDoubleLongHashMap( TDoubleLongMap map ) { + super( map.size() ); + if ( map instanceof TDoubleLongHashMap ) { + TDoubleLongHashMap hashmap = ( TDoubleLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + long oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public long put( double key, long value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( double key, long value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private long doPut( double key, long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().doubleValue(), entry.getValue().longValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleLongMap map ) { + ensureCapacity( map.size() ); + TDoubleLongIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public long get( double key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public long remove( double key ) { + long prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + byte[] states = _states; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TDoubleLongIterator iterator() { + return new TDoubleLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TLongProcedure procedure ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleLongProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleLongProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + long[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( double key ) { + return adjustValue( key, ( long ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( double key, long amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( double key, long adjust_amount, long put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleLongKeyHashIterator( TDoubleLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleLongHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleLongHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleLongHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleLongMap + *

+ * {@inheritDoc} + */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return no_entry_value != TDoubleLongHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleLongHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleLongHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleLongHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleLongHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TDoubleSet)) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TDoubleProcedure() { + private boolean first = true; + + + public boolean execute( double key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TDoubleLongValueHashIterator( TDoubleLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TDoubleLongHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TDoubleLongHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TDoubleLongHashMap.this.values( dest ); + } + + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + double[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TDoubleLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TDoubleLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TDoubleLongHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TDoubleLongKeyHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleLongKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TDoubleLongValueHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleLongValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TDoubleLongHashIterator extends THashPrimitiveIterator implements TDoubleLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TDoubleLongHashMap we will be iterating over. + */ + TDoubleLongHashIterator( TDoubleLongHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleLongMap ) ) { + return false; + } + TDoubleLongMap that = ( TDoubleLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + long[] values = _values; + byte[] states = _states; + long this_no_entry_value = getNoEntryValue(); + long that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + double key = _set[i]; + long that_value = that.get( key ); + long this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TDoubleLongProcedure() { + private boolean first = true; + public boolean execute( double key, long value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + long val = in.readLong(); + put(key, val); + } + } +} // TDoubleLongHashMap diff --git a/src/gnu/trove/map/hash/TDoubleObjectHashMap.java b/src/gnu/trove/map/hash/TDoubleObjectHashMap.java new file mode 100644 index 0000000..1084497 --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleObjectHashMap.java @@ -0,0 +1,1030 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import gnu.trove.TDoubleCollection; +import gnu.trove.function.TObjectFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TDoubleObjectIterator; +import gnu.trove.map.TDoubleObjectMap; +import gnu.trove.procedure.TDoubleObjectProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.set.TDoubleSet; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for double keys and Object values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TDoubleObjectHashMap extends TDoubleHash implements + TDoubleObjectMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TDoubleObjectProcedure PUT_ALL_PROC = new TDoubleObjectProcedure() { + public boolean execute( double key, V value) { + put( key, value ); + return true; + } + }; + + /** the values of the map */ + protected transient V[] _values; + + /** the value that represents null in the key set. */ + protected double no_entry_key; + + + /** + * Creates a new TDoubleObjectHashMap instance with the default + * capacity and load factor. + */ + public TDoubleObjectHashMap() { + super(); + } + + + /** + * Creates a new TDoubleObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleObjectHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TDoubleObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleObjectHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_key = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TDoubleObjectHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryKey the value used to represent null in the key set. + */ + public TDoubleObjectHashMap( int initialCapacity, float loadFactor, double noEntryKey ) { + super( initialCapacity, loadFactor ); + no_entry_key = noEntryKey; + } + + + /** + * Creates a new TDoubleObjectHashMap that contains the entries + * in the map passed to it. + * + * @param map the TDoubleObjectMap to be copied. + */ + public TDoubleObjectHashMap( TDoubleObjectMap map ) { + this( map.size(), 0.5f, map.getNoEntryKey() ); + putAll( map ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = ( V[] ) new Object[capacity]; + return capacity; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + V oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = (V[]) new Object[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey(o); + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public double getNoEntryKey() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( Object val ) { + byte[] states = _states; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && null == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && + ( val == vals[i] || val.equals( vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + /** {@inheritDoc} */ + public V get( double key ) { + int index = index( key ); + return index < 0 ? null : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public V put( double key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public V putIfAbsent( double key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + @SuppressWarnings({}) + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public V remove( double key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleObjectMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _states, 0, _states.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + // Views + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] dest ) { + if ( dest.length < _size ) { + dest = new double[_size]; + } + + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = k[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public Collection valueCollection() { + return new ValueView(); + } + + + /** {@inheritDoc} */ + public Object[] values() { + Object[] vals = new Object[size()]; + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public V[] values( V[] dest ) { + if ( dest.length < _size ) { + dest = ( V[] ) java.lang.reflect.Array.newInstance( + dest.getClass().getComponentType(), _size); + } + + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = ( V ) v[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public TDoubleObjectIterator iterator() { + return new TDoubleObjectHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TObjectProcedure procedure ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleObjectProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (states[i] == FULL && ! procedure.execute(keys[i],values[i])) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleObjectProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public void transformValues( TObjectFunction function ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** {@inheritDoc} */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleObjectMap ) ) { + return false; + } + TDoubleObjectMap that = ( TDoubleObjectMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TDoubleObjectIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + double key = iter.key(); + Object value = iter.value(); + if ( value == null ) { + if ( !( that.get( key ) == null && that.containsKey( key ) ) ) { + return false; + } + } else { + if ( !value.equals( that.get( key ) ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + V[] values = _values; + byte[] states = _states; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + ( values[i] == null ? 0 : values[i].hashCode() ); + } + } + return hashcode; + } + + + class KeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _size == 0; + } + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleObjectHashMap.this.containsKey( entry ); + } + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleHashIterator( TDoubleObjectHashMap.this ); + } + + /** {@inheritDoc} */ + public double[] toArray() { + return keys(); + } + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return keys( dest ); + } + + /** {@inheritDoc} */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return null != TDoubleObjectHashMap.this.remove( entry ); + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( ! TDoubleObjectHashMap.this.containsKey( + ( ( Double ) element ).doubleValue() ) ) { + + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + if ( collection == this ) { + return true; + } + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleObjectHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleObjectHashMap.this.containsKey( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + //noinspection SuspiciousMethodCalls + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TDoubleObjectHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleObjectHashMap.this.forEachKey( procedure ); + } + + /** {@inheritDoc) */ + public boolean equals( Object other ) { + if (! ( other instanceof TDoubleSet ) ) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( first ) first = false; + else buf.append( "," ); + buf.append( _set[i] ); + } + } + return buf.toString(); + } + + + class TDoubleHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** the collection on which the iterator operates */ + private final TDoubleHash _hash; + + /** {@inheritDoc} */ + public TDoubleHashIterator( TDoubleHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + public Iterator iterator() { + return new TDoubleObjectValueHashIterator( TDoubleObjectHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + public boolean removeElement( V value ) { + V[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + if ( value == values[i] || + ( null != values[i] && values[i].equals( value ) ) ) { + removeAt( i ); + return true; + } + } + } + return false; + } + + class TDoubleObjectValueHashIterator extends THashPrimitiveIterator + implements Iterator { + + @SuppressWarnings("rawtypes") + protected final TDoubleObjectHashMap _map; + + @SuppressWarnings("rawtypes") + public TDoubleObjectValueHashIterator( TDoubleObjectHashMap map ) { + super( map ); + _map = map; + } + + @SuppressWarnings("unchecked") + protected V objectAtIndex( int index ) { + byte[] states = _states; + Object value = _map._values[index]; + if ( states[index] != FULL ) { + return null; + } + return ( V ) value; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public V next() { + moveToNextIndex(); + return ( V ) _map._values[_index]; + } + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TDoubleObjectHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TDoubleObjectHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TDoubleObjectHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + @SuppressWarnings("hiding") + class TDoubleObjectHashIterator extends THashPrimitiveIterator + implements TDoubleObjectIterator { + + /** the collection being iterated over */ + private final TDoubleObjectHashMap _map; + + /** + * Creates an iterator over the specified map + * + * @param map map to iterate over. + */ + public TDoubleObjectHashIterator( TDoubleObjectHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _map._set[_index]; + } + + /** {@inheritDoc} */ + public V value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public V setValue( V val ) { + V old = value(); + _map._values[_index] = val; + return old; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeDouble( no_entry_key ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readDouble(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + V val = (V) in.readObject(); + put(key, val); + } + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TDoubleObjectProcedure() { + private boolean first = true; + public boolean execute(double key, Object value) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } +} // TDoubleObjectHashMap diff --git a/src/gnu/trove/map/hash/TDoubleShortHashMap.java b/src/gnu/trove/map/hash/TDoubleShortHashMap.java new file mode 100644 index 0000000..732f967 --- /dev/null +++ b/src/gnu/trove/map/hash/TDoubleShortHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.TShortCollection; +import gnu.trove.function.TShortFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TDoubleShortHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TDoubleShortIterator; +import gnu.trove.iterator.TShortIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TDoubleShortMap; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TDoubleShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TDoubleSet; + +/** + * An open addressed Map implementation for double keys and short values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TDoubleShortHashMap extends TDoubleShortHash implements TDoubleShortMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient short[] _values; + + + /** + * Creates a new TDoubleShortHashMap instance with the default + * capacity and load factor. + */ + public TDoubleShortHashMap() { + super(); + } + + + /** + * Creates a new TDoubleShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleShortHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TDoubleShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TDoubleShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TDoubleShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a double value that represents + * null for the Key set. + * @param noEntryValue a short value that represents + * null for the Value set. + */ + public TDoubleShortHashMap( int initialCapacity, float loadFactor, + double noEntryKey, short noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TDoubleShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a double array containing the keys for the matching values. + * @param values a short array containing the values. + */ + public TDoubleShortHashMap( double[] keys, short[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TDoubleShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TDoubleShortMap that will be duplicated. + */ + public TDoubleShortHashMap( TDoubleShortMap map ) { + super( map.size() ); + if ( map instanceof TDoubleShortHashMap ) { + TDoubleShortHashMap hashmap = ( TDoubleShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldKeys[] = _set; + short oldVals[] = _values; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _values = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public short put( double key, short value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( double key, short value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private short doPut( double key, short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().doubleValue(), entry.getValue().shortValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TDoubleShortMap map ) { + ensureCapacity( map.size() ); + TDoubleShortIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public short get( double key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public short remove( double key ) { + short prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TDoubleSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public double[] keys() { + double[] keys = new double[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + double[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public double[] keys( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + byte[] states = _states; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( double key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TDoubleShortIterator iterator() { + return new TDoubleShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TDoubleProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TShortProcedure procedure ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TDoubleShortProcedure procedure ) { + byte[] states = _states; + double[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TDoubleShortProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + double[] keys = _set; + short[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( double key ) { + return adjustValue( key, ( short ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( double key, short amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( double key, short adjust_amount, short put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TDoubleSet { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleShortKeyHashIterator( TDoubleShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TDoubleShortHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TDoubleShortHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TDoubleShortHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleShortMap + *

+ * {@inheritDoc} + */ + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + return no_entry_value != TDoubleShortHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TDoubleShortHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleShortHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TDoubleShortHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TDoubleShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TDoubleShortHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TDoubleSet)) { + return false; + } + final TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TDoubleProcedure() { + private boolean first = true; + + + public boolean execute( double key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TDoubleShortValueHashIterator( TDoubleShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TDoubleShortHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TDoubleShortHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TDoubleShortHashMap.this.values( dest ); + } + + + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + double[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TDoubleShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TDoubleShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TDoubleShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TDoubleShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TDoubleShortHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TDoubleShortKeyHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleShortKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TDoubleShortValueHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TDoubleShortValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TDoubleShortHashIterator extends THashPrimitiveIterator implements TDoubleShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TDoubleShortHashMap we will be iterating over. + */ + TDoubleShortHashIterator( TDoubleShortHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public double key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TDoubleShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleShortMap ) ) { + return false; + } + TDoubleShortMap that = ( TDoubleShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + short[] values = _values; + byte[] states = _states; + short this_no_entry_value = getNoEntryValue(); + short that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + double key = _set[i]; + short that_value = that.get( key ); + short this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TDoubleShortProcedure() { + private boolean first = true; + public boolean execute( double key, short value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + double key = in.readDouble(); + short val = in.readShort(); + put(key, val); + } + } +} // TDoubleShortHashMap diff --git a/src/gnu/trove/map/hash/TFloatByteHashMap.java b/src/gnu/trove/map/hash/TFloatByteHashMap.java new file mode 100644 index 0000000..d81efd4 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatByteHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TByteCollection; +import gnu.trove.TFloatCollection; +import gnu.trove.function.TByteFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TFloatByteHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.TFloatByteIterator; +import gnu.trove.iterator.TFloatIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TFloatByteMap; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.procedure.TFloatByteProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + +/** + * An open addressed Map implementation for float keys and byte values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TFloatByteHashMap extends TFloatByteHash implements TFloatByteMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient byte[] _values; + + + /** + * Creates a new TFloatByteHashMap instance with the default + * capacity and load factor. + */ + public TFloatByteHashMap() { + super(); + } + + + /** + * Creates a new TFloatByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatByteHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TFloatByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TFloatByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a float value that represents + * null for the Key set. + * @param noEntryValue a byte value that represents + * null for the Value set. + */ + public TFloatByteHashMap( int initialCapacity, float loadFactor, + float noEntryKey, byte noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TFloatByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a float array containing the keys for the matching values. + * @param values a byte array containing the values. + */ + public TFloatByteHashMap( float[] keys, byte[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TFloatByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TFloatByteMap that will be duplicated. + */ + public TFloatByteHashMap( TFloatByteMap map ) { + super( map.size() ); + if ( map instanceof TFloatByteHashMap ) { + TFloatByteHashMap hashmap = ( TFloatByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + byte oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public byte put( float key, byte value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( float key, byte value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private byte doPut( float key, byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().floatValue(), entry.getValue().byteValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatByteMap map ) { + ensureCapacity( map.size() ); + TFloatByteIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public byte get( float key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public byte remove( float key ) { + byte prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public float[] keys() { + float[] keys = new float[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public float[] keys( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + byte[] states = _states; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TFloatByteIterator iterator() { + return new TFloatByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TByteProcedure procedure ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TFloatByteProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TFloatByteProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + byte[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( float key ) { + return adjustValue( key, ( byte ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( float key, byte amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( float key, byte adjust_amount, byte put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TFloatSet { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatByteKeyHashIterator( TFloatByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatByteHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatByteHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatByteHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatByteMap + *

+ * {@inheritDoc} + */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return no_entry_value != TFloatByteHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatByteHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatByteHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatByteHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatByteHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TFloatSet)) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TFloatProcedure() { + private boolean first = true; + + + public boolean execute( float key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TFloatByteValueHashIterator( TFloatByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TFloatByteHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TFloatByteHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TFloatByteHashMap.this.values( dest ); + } + + + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + float[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TFloatByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TFloatByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TFloatByteHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TFloatByteKeyHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatByteKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TFloatByteValueHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatByteValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TFloatByteHashIterator extends THashPrimitiveIterator implements TFloatByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TFloatByteHashMap we will be iterating over. + */ + TFloatByteHashIterator( TFloatByteHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatByteMap ) ) { + return false; + } + TFloatByteMap that = ( TFloatByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + byte[] values = _values; + byte[] states = _states; + byte this_no_entry_value = getNoEntryValue(); + byte that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + float key = _set[i]; + byte that_value = that.get( key ); + byte this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TFloatByteProcedure() { + private boolean first = true; + public boolean execute( float key, byte value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + byte val = in.readByte(); + put(key, val); + } + } +} // TFloatByteHashMap diff --git a/src/gnu/trove/map/hash/TFloatCharHashMap.java b/src/gnu/trove/map/hash/TFloatCharHashMap.java new file mode 100644 index 0000000..1228ff1 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatCharHashMap.java @@ -0,0 +1,1308 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TCharCollection; +import gnu.trove.TFloatCollection; +import gnu.trove.function.TCharFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TFloatCharHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.TFloatCharIterator; +import gnu.trove.iterator.TFloatIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TFloatCharMap; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.procedure.TFloatCharProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + +/** + * An open addressed Map implementation for float keys and char values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TFloatCharHashMap extends TFloatCharHash implements TFloatCharMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient char[] _values; + + + /** + * Creates a new TFloatCharHashMap instance with the default + * capacity and load factor. + */ + public TFloatCharHashMap() { + super(); + } + + + /** + * Creates a new TFloatCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatCharHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TFloatCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TFloatCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a float value that represents + * null for the Key set. + * @param noEntryValue a char value that represents + * null for the Value set. + */ + public TFloatCharHashMap( int initialCapacity, float loadFactor, + float noEntryKey, char noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TFloatCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a float array containing the keys for the matching values. + * @param values a char array containing the values. + */ + public TFloatCharHashMap( float[] keys, char[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TFloatCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TFloatCharMap that will be duplicated. + */ + public TFloatCharHashMap( TFloatCharMap map ) { + super( map.size() ); + if ( map instanceof TFloatCharHashMap ) { + TFloatCharHashMap hashmap = ( TFloatCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + char oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public char put( float key, char value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( float key, char value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private char doPut( float key, char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().floatValue(), entry.getValue().charValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatCharMap map ) { + ensureCapacity( map.size() ); + TFloatCharIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public char get( float key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public char remove( float key ) { + char prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public float[] keys() { + float[] keys = new float[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public float[] keys( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + byte[] states = _states; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TFloatCharIterator iterator() { + return new TFloatCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TCharProcedure procedure ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TFloatCharProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TFloatCharProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + char[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( float key ) { + return adjustValue( key, ( char ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( float key, char amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( float key, char adjust_amount, char put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TFloatSet { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatCharKeyHashIterator( TFloatCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatCharHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatCharHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatCharHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatCharMap + *

+ * {@inheritDoc} + */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return no_entry_value != TFloatCharHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatCharHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatCharHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatCharHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatCharHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TFloatSet)) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TFloatProcedure() { + private boolean first = true; + + + public boolean execute( float key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TFloatCharValueHashIterator( TFloatCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TFloatCharHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TFloatCharHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TFloatCharHashMap.this.values( dest ); + } + + + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + float[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TFloatCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TFloatCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TFloatCharHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TFloatCharKeyHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatCharKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TFloatCharValueHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatCharValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TFloatCharHashIterator extends THashPrimitiveIterator implements TFloatCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TFloatCharHashMap we will be iterating over. + */ + TFloatCharHashIterator( TFloatCharHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatCharMap ) ) { + return false; + } + TFloatCharMap that = ( TFloatCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + char[] values = _values; + byte[] states = _states; + char this_no_entry_value = getNoEntryValue(); + char that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + float key = _set[i]; + char that_value = that.get( key ); + char this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TFloatCharProcedure() { + private boolean first = true; + public boolean execute( float key, char value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + char val = in.readChar(); + put(key, val); + } + } +} // TFloatCharHashMap diff --git a/src/gnu/trove/map/hash/TFloatDoubleHashMap.java b/src/gnu/trove/map/hash/TFloatDoubleHashMap.java new file mode 100644 index 0000000..c09bd21 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatDoubleHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.TFloatCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TFloatDoubleHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TFloatDoubleIterator; +import gnu.trove.iterator.TFloatIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TFloatDoubleMap; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TFloatDoubleProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + +/** + * An open addressed Map implementation for float keys and double values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TFloatDoubleHashMap extends TFloatDoubleHash implements TFloatDoubleMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient double[] _values; + + + /** + * Creates a new TFloatDoubleHashMap instance with the default + * capacity and load factor. + */ + public TFloatDoubleHashMap() { + super(); + } + + + /** + * Creates a new TFloatDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TFloatDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TFloatDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a float value that represents + * null for the Key set. + * @param noEntryValue a double value that represents + * null for the Value set. + */ + public TFloatDoubleHashMap( int initialCapacity, float loadFactor, + float noEntryKey, double noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TFloatDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a float array containing the keys for the matching values. + * @param values a double array containing the values. + */ + public TFloatDoubleHashMap( float[] keys, double[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TFloatDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TFloatDoubleMap that will be duplicated. + */ + public TFloatDoubleHashMap( TFloatDoubleMap map ) { + super( map.size() ); + if ( map instanceof TFloatDoubleHashMap ) { + TFloatDoubleHashMap hashmap = ( TFloatDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + double oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public double put( float key, double value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( float key, double value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private double doPut( float key, double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().floatValue(), entry.getValue().doubleValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatDoubleMap map ) { + ensureCapacity( map.size() ); + TFloatDoubleIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public double get( float key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public double remove( float key ) { + double prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public float[] keys() { + float[] keys = new float[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public float[] keys( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + byte[] states = _states; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TFloatDoubleIterator iterator() { + return new TFloatDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TFloatDoubleProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TFloatDoubleProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + double[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( float key ) { + return adjustValue( key, ( double ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( float key, double amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( float key, double adjust_amount, double put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TFloatSet { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatDoubleKeyHashIterator( TFloatDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatDoubleHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatDoubleHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatDoubleHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatDoubleMap + *

+ * {@inheritDoc} + */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return no_entry_value != TFloatDoubleHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatDoubleHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatDoubleHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatDoubleHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatDoubleHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TFloatSet)) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TFloatProcedure() { + private boolean first = true; + + + public boolean execute( float key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TFloatDoubleValueHashIterator( TFloatDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TFloatDoubleHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TFloatDoubleHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TFloatDoubleHashMap.this.values( dest ); + } + + + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + float[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TFloatDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TFloatDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TFloatDoubleHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TFloatDoubleKeyHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatDoubleKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TFloatDoubleValueHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatDoubleValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TFloatDoubleHashIterator extends THashPrimitiveIterator implements TFloatDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TFloatDoubleHashMap we will be iterating over. + */ + TFloatDoubleHashIterator( TFloatDoubleHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatDoubleMap ) ) { + return false; + } + TFloatDoubleMap that = ( TFloatDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + double[] values = _values; + byte[] states = _states; + double this_no_entry_value = getNoEntryValue(); + double that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + float key = _set[i]; + double that_value = that.get( key ); + double this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TFloatDoubleProcedure() { + private boolean first = true; + public boolean execute( float key, double value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + double val = in.readDouble(); + put(key, val); + } + } +} // TFloatDoubleHashMap diff --git a/src/gnu/trove/map/hash/TFloatFloatHashMap.java b/src/gnu/trove/map/hash/TFloatFloatHashMap.java new file mode 100644 index 0000000..bc89083 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatFloatHashMap.java @@ -0,0 +1,1307 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TFloatCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TFloatFloatHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TFloatFloatIterator; +import gnu.trove.iterator.TFloatIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TFloatFloatMap; +import gnu.trove.procedure.TFloatFloatProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.set.TFloatSet; + +/** + * An open addressed Map implementation for float keys and float values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TFloatFloatHashMap extends TFloatFloatHash implements TFloatFloatMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient float[] _values; + + + /** + * Creates a new TFloatFloatHashMap instance with the default + * capacity and load factor. + */ + public TFloatFloatHashMap() { + super(); + } + + + /** + * Creates a new TFloatFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TFloatFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TFloatFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a float value that represents + * null for the Key set. + * @param noEntryValue a float value that represents + * null for the Value set. + */ + public TFloatFloatHashMap( int initialCapacity, float loadFactor, + float noEntryKey, float noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TFloatFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a float array containing the keys for the matching values. + * @param values a float array containing the values. + */ + public TFloatFloatHashMap( float[] keys, float[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TFloatFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TFloatFloatMap that will be duplicated. + */ + public TFloatFloatHashMap( TFloatFloatMap map ) { + super( map.size() ); + if ( map instanceof TFloatFloatHashMap ) { + TFloatFloatHashMap hashmap = ( TFloatFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + float oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public float put( float key, float value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( float key, float value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private float doPut( float key, float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().floatValue(), entry.getValue().floatValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatFloatMap map ) { + ensureCapacity( map.size() ); + TFloatFloatIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public float get( float key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public float remove( float key ) { + float prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public float[] keys() { + float[] keys = new float[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public float[] keys( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + byte[] states = _states; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TFloatFloatIterator iterator() { + return new TFloatFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TFloatProcedure procedure ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TFloatFloatProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TFloatFloatProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + float[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( float key ) { + return adjustValue( key, ( float ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( float key, float amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( float key, float adjust_amount, float put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TFloatSet { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatFloatKeyHashIterator( TFloatFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatFloatHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatFloatHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatFloatHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatFloatMap + *

+ * {@inheritDoc} + */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return no_entry_value != TFloatFloatHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatFloatHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatFloatHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatFloatHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatFloatHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TFloatSet)) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TFloatProcedure() { + private boolean first = true; + + + public boolean execute( float key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatFloatValueHashIterator( TFloatFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatFloatHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatFloatHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatFloatHashMap.this.values( dest ); + } + + + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + float[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatFloatHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TFloatFloatKeyHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatFloatKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TFloatFloatValueHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatFloatValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TFloatFloatHashIterator extends THashPrimitiveIterator implements TFloatFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TFloatFloatHashMap we will be iterating over. + */ + TFloatFloatHashIterator( TFloatFloatHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatFloatMap ) ) { + return false; + } + TFloatFloatMap that = ( TFloatFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + float[] values = _values; + byte[] states = _states; + float this_no_entry_value = getNoEntryValue(); + float that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + float key = _set[i]; + float that_value = that.get( key ); + float this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TFloatFloatProcedure() { + private boolean first = true; + public boolean execute( float key, float value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + float val = in.readFloat(); + put(key, val); + } + } +} // TFloatFloatHashMap diff --git a/src/gnu/trove/map/hash/TFloatIntHashMap.java b/src/gnu/trove/map/hash/TFloatIntHashMap.java new file mode 100644 index 0000000..e79a7e3 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatIntHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TFloatCollection; +import gnu.trove.TIntCollection; +import gnu.trove.function.TIntFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TFloatIntHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TFloatIntIterator; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TIntIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TFloatIntMap; +import gnu.trove.procedure.TFloatIntProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TFloatSet; + +/** + * An open addressed Map implementation for float keys and int values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TFloatIntHashMap extends TFloatIntHash implements TFloatIntMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient int[] _values; + + + /** + * Creates a new TFloatIntHashMap instance with the default + * capacity and load factor. + */ + public TFloatIntHashMap() { + super(); + } + + + /** + * Creates a new TFloatIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatIntHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TFloatIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TFloatIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a float value that represents + * null for the Key set. + * @param noEntryValue a int value that represents + * null for the Value set. + */ + public TFloatIntHashMap( int initialCapacity, float loadFactor, + float noEntryKey, int noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TFloatIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a float array containing the keys for the matching values. + * @param values a int array containing the values. + */ + public TFloatIntHashMap( float[] keys, int[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TFloatIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TFloatIntMap that will be duplicated. + */ + public TFloatIntHashMap( TFloatIntMap map ) { + super( map.size() ); + if ( map instanceof TFloatIntHashMap ) { + TFloatIntHashMap hashmap = ( TFloatIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + int oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public int put( float key, int value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( float key, int value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private int doPut( float key, int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().floatValue(), entry.getValue().intValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatIntMap map ) { + ensureCapacity( map.size() ); + TFloatIntIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public int get( float key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public int remove( float key ) { + int prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public float[] keys() { + float[] keys = new float[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public float[] keys( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + byte[] states = _states; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TFloatIntIterator iterator() { + return new TFloatIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TIntProcedure procedure ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TFloatIntProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TFloatIntProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + int[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( float key ) { + return adjustValue( key, ( int ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( float key, int amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( float key, int adjust_amount, int put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TFloatSet { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatIntKeyHashIterator( TFloatIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatIntHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatIntHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatIntHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatIntMap + *

+ * {@inheritDoc} + */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return no_entry_value != TFloatIntHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatIntHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatIntHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatIntHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatIntHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TFloatSet)) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TFloatProcedure() { + private boolean first = true; + + + public boolean execute( float key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TFloatIntValueHashIterator( TFloatIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TFloatIntHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TFloatIntHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TFloatIntHashMap.this.values( dest ); + } + + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + float[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TFloatIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TFloatIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TFloatIntHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TFloatIntKeyHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatIntKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TFloatIntValueHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatIntValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TFloatIntHashIterator extends THashPrimitiveIterator implements TFloatIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TFloatIntHashMap we will be iterating over. + */ + TFloatIntHashIterator( TFloatIntHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatIntMap ) ) { + return false; + } + TFloatIntMap that = ( TFloatIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + int[] values = _values; + byte[] states = _states; + int this_no_entry_value = getNoEntryValue(); + int that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + float key = _set[i]; + int that_value = that.get( key ); + int this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TFloatIntProcedure() { + private boolean first = true; + public boolean execute( float key, int value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + int val = in.readInt(); + put(key, val); + } + } +} // TFloatIntHashMap diff --git a/src/gnu/trove/map/hash/TFloatLongHashMap.java b/src/gnu/trove/map/hash/TFloatLongHashMap.java new file mode 100644 index 0000000..c14a3d1 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatLongHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TFloatCollection; +import gnu.trove.TLongCollection; +import gnu.trove.function.TLongFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TFloatLongHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TFloatLongIterator; +import gnu.trove.iterator.TLongIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TFloatLongMap; +import gnu.trove.procedure.TFloatLongProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TFloatSet; + +/** + * An open addressed Map implementation for float keys and long values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TFloatLongHashMap extends TFloatLongHash implements TFloatLongMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient long[] _values; + + + /** + * Creates a new TFloatLongHashMap instance with the default + * capacity and load factor. + */ + public TFloatLongHashMap() { + super(); + } + + + /** + * Creates a new TFloatLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatLongHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TFloatLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TFloatLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a float value that represents + * null for the Key set. + * @param noEntryValue a long value that represents + * null for the Value set. + */ + public TFloatLongHashMap( int initialCapacity, float loadFactor, + float noEntryKey, long noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TFloatLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a float array containing the keys for the matching values. + * @param values a long array containing the values. + */ + public TFloatLongHashMap( float[] keys, long[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TFloatLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TFloatLongMap that will be duplicated. + */ + public TFloatLongHashMap( TFloatLongMap map ) { + super( map.size() ); + if ( map instanceof TFloatLongHashMap ) { + TFloatLongHashMap hashmap = ( TFloatLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + long oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public long put( float key, long value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( float key, long value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private long doPut( float key, long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().floatValue(), entry.getValue().longValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatLongMap map ) { + ensureCapacity( map.size() ); + TFloatLongIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public long get( float key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public long remove( float key ) { + long prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public float[] keys() { + float[] keys = new float[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public float[] keys( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + byte[] states = _states; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TFloatLongIterator iterator() { + return new TFloatLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TLongProcedure procedure ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TFloatLongProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TFloatLongProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + long[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( float key ) { + return adjustValue( key, ( long ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( float key, long amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( float key, long adjust_amount, long put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TFloatSet { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatLongKeyHashIterator( TFloatLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatLongHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatLongHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatLongHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatLongMap + *

+ * {@inheritDoc} + */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return no_entry_value != TFloatLongHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatLongHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatLongHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatLongHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatLongHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TFloatSet)) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TFloatProcedure() { + private boolean first = true; + + + public boolean execute( float key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TFloatLongValueHashIterator( TFloatLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TFloatLongHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TFloatLongHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TFloatLongHashMap.this.values( dest ); + } + + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + float[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TFloatLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TFloatLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TFloatLongHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TFloatLongKeyHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatLongKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TFloatLongValueHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatLongValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TFloatLongHashIterator extends THashPrimitiveIterator implements TFloatLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TFloatLongHashMap we will be iterating over. + */ + TFloatLongHashIterator( TFloatLongHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatLongMap ) ) { + return false; + } + TFloatLongMap that = ( TFloatLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + long[] values = _values; + byte[] states = _states; + long this_no_entry_value = getNoEntryValue(); + long that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + float key = _set[i]; + long that_value = that.get( key ); + long this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TFloatLongProcedure() { + private boolean first = true; + public boolean execute( float key, long value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + long val = in.readLong(); + put(key, val); + } + } +} // TFloatLongHashMap diff --git a/src/gnu/trove/map/hash/TFloatObjectHashMap.java b/src/gnu/trove/map/hash/TFloatObjectHashMap.java new file mode 100644 index 0000000..effab27 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatObjectHashMap.java @@ -0,0 +1,1036 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import gnu.trove.TFloatCollection; +import gnu.trove.function.TObjectFunction; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TFloatHash; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TFloatObjectIterator; +import gnu.trove.map.TFloatObjectMap; +import gnu.trove.procedure.TFloatObjectProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.set.TFloatSet; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for float keys and Object values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TFloatObjectHashMap extends TFloatHash implements + TFloatObjectMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TFloatObjectProcedure PUT_ALL_PROC = new TFloatObjectProcedure() { + public boolean execute( float key, V value) { + put( key, value ); + return true; + } + }; + + /** the values of the map */ + protected transient V[] _values; + + /** the value that represents null in the key set. */ + protected float no_entry_key; + + + /** + * Creates a new TFloatObjectHashMap instance with the default + * capacity and load factor. + */ + public TFloatObjectHashMap() { + super(); + } + + + /** + * Creates a new TFloatObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatObjectHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TFloatObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatObjectHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_key = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TFloatObjectHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryKey the value used to represent null in the key set. + */ + public TFloatObjectHashMap( int initialCapacity, float loadFactor, float noEntryKey ) { + super( initialCapacity, loadFactor ); + no_entry_key = noEntryKey; + } + + + /** + * Creates a new TFloatObjectHashMap that contains the entries + * in the map passed to it. + * + * @param map the TFloatObjectMap to be copied. + */ + public TFloatObjectHashMap( TFloatObjectMap map ) { + this( map.size(), 0.5f, map.getNoEntryKey() ); + putAll( map ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = ( V[] ) new Object[capacity]; + return capacity; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + V oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = (V[]) new Object[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey(o); + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public float getNoEntryKey() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( Object val ) { + byte[] states = _states; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && null == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && + ( val == vals[i] || val.equals( vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + /** {@inheritDoc} */ + public V get( float key ) { + int index = index( key ); + return index < 0 ? null : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public V put( float key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public V putIfAbsent( float key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public V remove( float key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatObjectMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _states, 0, _states.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + // Views + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public float[] keys() { + float[] keys = new float[size()]; + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public float[] keys( float[] dest ) { + if ( dest.length < _size ) { + dest = new float[_size]; + } + + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = k[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public Collection valueCollection() { + return new ValueView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public Object[] values() { + Object[] vals = new Object[size()]; + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public V[] values( V[] dest ) { + if ( dest.length < _size ) { + dest = ( V[] ) java.lang.reflect.Array.newInstance( + dest.getClass().getComponentType(), _size); + } + + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = ( V ) v[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public TFloatObjectIterator iterator() { + return new TFloatObjectHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TObjectProcedure procedure ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean forEachEntry( TFloatObjectProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (states[i] == FULL && ! procedure.execute(keys[i],values[i])) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainEntries( TFloatObjectProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public void transformValues( TObjectFunction function ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** {@inheritDoc} */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatObjectMap ) ) { + return false; + } + TFloatObjectMap that = ( TFloatObjectMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TFloatObjectIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + float key = iter.key(); + Object value = iter.value(); + if ( value == null ) { + if ( !( that.get( key ) == null && that.containsKey( key ) ) ) { + return false; + } + } else { + if ( !value.equals( that.get( key ) ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + V[] values = _values; + byte[] states = _states; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + ( values[i] == null ? 0 : values[i].hashCode() ); + } + } + return hashcode; + } + + + class KeyView implements TFloatSet { + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _size == 0; + } + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatObjectHashMap.this.containsKey( entry ); + } + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatHashIterator( TFloatObjectHashMap.this ); + } + + /** {@inheritDoc} */ + public float[] toArray() { + return keys(); + } + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return keys( dest ); + } + + /** {@inheritDoc} */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return null != TFloatObjectHashMap.this.remove( entry ); + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( ! TFloatObjectHashMap.this.containsKey( + ( ( Float ) element ).floatValue() ) ) { + + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + if ( collection == this ) { + return true; + } + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatObjectHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatObjectHashMap.this.containsKey( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + //noinspection SuspiciousMethodCalls + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TFloatObjectHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatObjectHashMap.this.forEachKey( procedure ); + } + + /** {@inheritDoc) */ + public boolean equals( Object other ) { + if (! ( other instanceof TFloatSet ) ) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( first ) first = false; + else buf.append( "," ); + buf.append( _set[i] ); + } + } + return buf.toString(); + } + + + class TFloatHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** the collection on which the iterator operates */ + private final TFloatHash _hash; + + /** {@inheritDoc} */ + public TFloatHashIterator( TFloatHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({}) + public Iterator iterator() { + return new TFloatObjectValueHashIterator( TFloatObjectHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + public boolean removeElement( V value ) { + V[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + if ( value == values[i] || + ( null != values[i] && values[i].equals( value ) ) ) { + removeAt( i ); + return true; + } + } + } + return false; + } + + class TFloatObjectValueHashIterator extends THashPrimitiveIterator + implements Iterator { + + @SuppressWarnings("rawtypes") + protected final TFloatObjectHashMap _map; + + @SuppressWarnings("rawtypes") + public TFloatObjectValueHashIterator( TFloatObjectHashMap map ) { + super( map ); + _map = map; + } + + @SuppressWarnings("unchecked") + protected V objectAtIndex( int index ) { + byte[] states = _states; + Object value = _map._values[index]; + if ( states[index] != FULL ) { + return null; + } + return ( V ) value; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public V next() { + moveToNextIndex(); + return ( V ) _map._values[_index]; + } + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TFloatObjectHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TFloatObjectHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TFloatObjectHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + @SuppressWarnings("hiding") + class TFloatObjectHashIterator extends THashPrimitiveIterator + implements TFloatObjectIterator { + + /** the collection being iterated over */ + private final TFloatObjectHashMap _map; + + /** + * Creates an iterator over the specified map + * + * @param map map to iterate over. + */ + public TFloatObjectHashIterator( TFloatObjectHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _map._set[_index]; + } + + /** {@inheritDoc} */ + public V value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public V setValue( V val ) { + V old = value(); + _map._values[_index] = val; + return old; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeFloat( no_entry_key ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readFloat(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + V val = (V) in.readObject(); + put(key, val); + } + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TFloatObjectProcedure() { + private boolean first = true; + public boolean execute(float key, Object value) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } +} // TFloatObjectHashMap diff --git a/src/gnu/trove/map/hash/TFloatShortHashMap.java b/src/gnu/trove/map/hash/TFloatShortHashMap.java new file mode 100644 index 0000000..5d7e385 --- /dev/null +++ b/src/gnu/trove/map/hash/TFloatShortHashMap.java @@ -0,0 +1,1300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TFloatShortMap; +import gnu.trove.function.TShortFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for float keys and short values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TFloatShortHashMap extends TFloatShortHash implements TFloatShortMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient short[] _values; + + + /** + * Creates a new TFloatShortHashMap instance with the default + * capacity and load factor. + */ + public TFloatShortHashMap() { + super(); + } + + + /** + * Creates a new TFloatShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatShortHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TFloatShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TFloatShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TFloatShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a float value that represents + * null for the Key set. + * @param noEntryValue a short value that represents + * null for the Value set. + */ + public TFloatShortHashMap( int initialCapacity, float loadFactor, + float noEntryKey, short noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TFloatShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a float array containing the keys for the matching values. + * @param values a short array containing the values. + */ + public TFloatShortHashMap( float[] keys, short[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TFloatShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TFloatShortMap that will be duplicated. + */ + public TFloatShortHashMap( TFloatShortMap map ) { + super( map.size() ); + if ( map instanceof TFloatShortHashMap ) { + TFloatShortHashMap hashmap = ( TFloatShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldKeys[] = _set; + short oldVals[] = _values; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _values = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public short put( float key, short value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( float key, short value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private short doPut( float key, short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().floatValue(), entry.getValue().shortValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TFloatShortMap map ) { + ensureCapacity( map.size() ); + TFloatShortIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public short get( float key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public short remove( float key ) { + short prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TFloatSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public float[] keys() { + float[] keys = new float[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + float[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public float[] keys( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + byte[] states = _states; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( float key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TFloatShortIterator iterator() { + return new TFloatShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TFloatProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TShortProcedure procedure ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TFloatShortProcedure procedure ) { + byte[] states = _states; + float[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TFloatShortProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + float[] keys = _set; + short[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( float key ) { + return adjustValue( key, ( short ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( float key, short amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( float key, short adjust_amount, short put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TFloatSet { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatShortKeyHashIterator( TFloatShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TFloatShortHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TFloatShortHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TFloatShortHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatShortMap + *

+ * {@inheritDoc} + */ + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + return no_entry_value != TFloatShortHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TFloatShortHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatShortHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TFloatShortHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TFloatShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TFloatShortHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TFloatSet)) { + return false; + } + final TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TFloatProcedure() { + private boolean first = true; + + + public boolean execute( float key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TFloatShortValueHashIterator( TFloatShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TFloatShortHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TFloatShortHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TFloatShortHashMap.this.values( dest ); + } + + + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + float[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TFloatShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TFloatShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TFloatShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TFloatShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TFloatShortHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TFloatShortKeyHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatShortKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TFloatShortValueHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TFloatShortValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TFloatShortHashIterator extends THashPrimitiveIterator implements TFloatShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TFloatShortHashMap we will be iterating over. + */ + TFloatShortHashIterator( TFloatShortHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public float key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TFloatShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatShortMap ) ) { + return false; + } + TFloatShortMap that = ( TFloatShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + short[] values = _values; + byte[] states = _states; + short this_no_entry_value = getNoEntryValue(); + short that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + float key = _set[i]; + short that_value = that.get( key ); + short this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TFloatShortProcedure() { + private boolean first = true; + public boolean execute( float key, short value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + float key = in.readFloat(); + short val = in.readShort(); + put(key, val); + } + } +} // TFloatShortHashMap diff --git a/src/gnu/trove/map/hash/THashMap.java b/src/gnu/trove/map/hash/THashMap.java new file mode 100644 index 0000000..7d71dce --- /dev/null +++ b/src/gnu/trove/map/hash/THashMap.java @@ -0,0 +1,915 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.function.TObjectFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.map.TMap; +import gnu.trove.procedure.TObjectObjectProcedure; +import gnu.trove.procedure.TObjectProcedure; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.*; + + +/** + * An implementation of the Map interface which uses an open addressed + * hash table to store its contents. + *

+ * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: THashMap.java,v 1.1.2.8 2010/03/02 04:09:50 robeden Exp $ + */ + +public class THashMap extends TObjectHash implements TMap, Externalizable { + + static final long serialVersionUID = 1L; + + /** + * the values of the map + */ + protected transient V[] _values; + + + /** + * Creates a new THashMap instance with the default + * capacity and load factor. + */ + public THashMap() { + super(); + } + + + /** + * Creates a new THashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public THashMap(int initialCapacity) { + super(initialCapacity); + } + + + /** + * Creates a new THashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public THashMap(int initialCapacity, float loadFactor) { + super(initialCapacity, loadFactor); + } + + + /** + * Creates a new THashMap instance which contains the + * key/value pairs in map. + * + * @param map a Map value + */ + public THashMap(Map map) { + this(map.size()); + putAll(map); + } + + + /** + * Creates a new THashMap instance which contains the + * key/value pairs in map. + * + * @param map a Map value + */ + public THashMap(THashMap map) { + this(map.size()); + putAll(map); + } + + + /** + * initialize the value array of the map. + * + * @param initialCapacity an int value + * @return an int value + */ + @SuppressWarnings("unchecked") + public int setUp(int initialCapacity) { + int capacity; + + capacity = super.setUp(initialCapacity); + //noinspection unchecked + _values = (V[]) new Object[capacity]; + return capacity; + } + + + /** + * Inserts a key/value pair into the map. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or {@code null} if none was found. + */ + public V put(K key, V value) { + // insertKey() inserts the key if a slot if found and returns the index + int index = insertKey(key); + return doPut(value, index); + } + + + /** + * Inserts a key/value pair into the map if the specified key is not already + * associated with a value. + * + * @param key an Object value + * @param value an Object value + * @return the previous value associated with key, + * or {@code null} if none was found. + */ + public V putIfAbsent(K key, V value) { + // insertKey() inserts the key if a slot if found and returns the index + int index = insertKey(key); + if (index < 0) { + return _values[-index - 1]; + } + return doPut(value, index); + } + + + private V doPut(V value, int index) { + V previous = null; + boolean isNewMapping = true; + if (index < 0) { + index = -index - 1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + if (isNewMapping) { + postInsertHook(consumeFreeSlot); + } + + return previous; + } + + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings({"unchecked"}) + public boolean equals(Object other) { + if (!(other instanceof Map)) { + return false; + } + Map that = (Map) other; + if (that.size() != this.size()) { + return false; + } + return forEachEntry(new EqProcedure(that)); + } + + + public int hashCode() { + HashProcedure p = new HashProcedure(); + forEachEntry(p); + return p.getHashCode(); + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TObjectObjectProcedure() { + private boolean first = true; + + + public boolean execute(K key, V value) { + if (first) { + first = false; + } else { + buf.append(", "); + } + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } + + + private final class HashProcedure implements TObjectObjectProcedure { + private int h = 0; + + public int getHashCode() { + return h; + } + + public final boolean execute(K key, V value) { + h += HashFunctions.hash(key) ^ (value == null ? 0 : value.hashCode()); + return true; + } + } + + + @SuppressWarnings("hiding") + private final class EqProcedure implements TObjectObjectProcedure { + private final Map _otherMap; + + EqProcedure(Map otherMap) { + _otherMap = otherMap; + } + + + public final boolean execute(K key, V value) { + // Check to make sure the key is there. This avoids problems that come up with + // null values. Since it is only caused in that cause, only do this when the + // value is null (to avoid extra work). + if (value == null && !_otherMap.containsKey(key)) { + return false; + } + + V oValue = _otherMap.get(key); + return oValue == value || (oValue != null && + THashMap.this.equals(oValue, value)); + } + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey(TObjectProcedure procedure) { + return forEach(procedure); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue(TObjectProcedure procedure) { + V[] values = _values; + Object[] set = _set; + for (int i = values.length; i-- > 0;) { + if (set[i] != FREE + && set[i] != REMOVED + && !procedure.execute(values[i])) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TObjectObjectProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry(TObjectObjectProcedure procedure) { + Object[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (keys[i] != FREE + && keys[i] != REMOVED + && !procedure.execute((K) keys[i], values[i])) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings({"unchecked"}) + public boolean retainEntries(TObjectObjectProcedure procedure) { + boolean modified = false; + Object[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for (int i = keys.length; i-- > 0;) { + if (keys[i] != FREE + && keys[i] != REMOVED + && !procedure.execute((K) keys[i], values[i])) { + removeAt(i); + modified = true; + } + } + } finally { + reenableAutoCompaction(true); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TObjectFunction value + */ + public void transformValues(TObjectFunction function) { + V[] values = _values; + Object[] set = _set; + for (int i = values.length; i-- > 0;) { + if (set[i] != FREE && set[i] != REMOVED) { + values[i] = function.execute(values[i]); + } + } + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings({"unchecked"}) + protected void rehash(int newCapacity) { + int oldCapacity = _set.length; + int oldSize = size(); + Object oldKeys[] = _set; + V oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill(_set, FREE); + _values = (V[]) new Object[newCapacity]; + + for (int i = oldCapacity; i-- > 0;) { + Object o = oldKeys[i]; + + if (o == FREE || o == REMOVED) continue; + + int index = insertKey((K) o); + if (index < 0) { + throwObjectContractViolation(_set[(-index - 1)], o, size(), oldSize, oldKeys); + } + _values[index] = oldVals[i]; + } + + // Last check: size before and after should be the same + reportPotentialConcurrentMod(size(), oldSize); + } + + + /** + * retrieves the value for key + * + * @param key an Object value + * @return the value of key or null if no such mapping exists. + */ + @SuppressWarnings({}) + public V get(Object key) { + int index = index(key); + return index < 0 ? null : _values[index]; + } + + + /** + * Empties the map. + */ + public void clear() { + if (size() == 0) { + return; // optimization + } + + super.clear(); + + Arrays.fill(_set, 0, _set.length, FREE); + Arrays.fill(_values, 0, _values.length, null); + } + + + /** + * Deletes a key/value pair from the map. + * + * @param key an Object value + * @return an Object value + */ + @SuppressWarnings({}) + public V remove(Object key) { + V prev = null; + int index = index(key); + if (index >= 0) { + prev = _values[index]; + removeAt(index); // clear key,state; adjust size + } + return prev; + } + + + /** + * removes the mapping at index from the map. + * + * @param index an int value + */ + public void removeAt(int index) { + _values[index] = null; + super.removeAt(index); // clear key, state; adjust size + } + + + /** + * Returns a view on the values of the map. + * + * @return a Collection value + */ + public Collection values() { + return new ValueView(); + } + + + /** + * returns a Set view on the keys of the map. + * + * @return a Set value + */ + public Set keySet() { + return new KeyView(); + } + + + /** + * Returns a Set view on the entries of the map. + * + * @return a Set value + */ + public Set> entrySet() { + return new EntryView(); + } + + + /** + * checks for the presence of val in the values of the map. + * + * @param val an Object value + * @return a boolean value + */ + public boolean containsValue(Object val) { + Object[] set = _set; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if (null == val) { + for (int i = vals.length; i-- > 0;) { + if ((set[i] != FREE && set[i] != REMOVED) && + val == vals[i]) { + return true; + } + } + } else { + for (int i = vals.length; i-- > 0;) { + if ((set[i] != FREE && set[i] != REMOVED) && + (val == vals[i] || equals(val, vals[i]))) { + return true; + } + } + } // end of else + return false; + } + + + /** + * checks for the present of key in the keys of the map. + * + * @param key an Object value + * @return a boolean value + */ + public boolean containsKey(Object key) { + //noinspection unchecked + return contains(key); + } + + + /** + * copies the key/value mappings in map into this map. + * + * @param map a Map value + */ + public void putAll(Map map) { + ensureCapacity(map.size()); + // could optimize this for cases when map instanceof THashMap + for (Map.Entry e : map.entrySet()) { + put(e.getKey(), e.getValue()); + } + } + + + /** + * a view onto the values of the map. + */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator(THashMap.this) { + protected V objectAtIndex(int index) { + return _values[index]; + } + }; + } + + + public boolean containsElement(V value) { + return containsValue(value); + } + + + public boolean removeElement(V value) { + Object[] values = _values; + Object[] set = _set; + + for (int i = values.length; i-- > 0;) { + if ((set[i] != FREE && set[i] != REMOVED) && + value == values[i] || + (null != values[i] && THashMap.this.equals(values[i], value))) { + + removeAt(i); + return true; + } + } + + return false; + } + } + + /** + * a view onto the entries of the map. + */ + protected class EntryView extends MapBackedView> { + + @SuppressWarnings("rawtypes") + private final class EntryIterator extends TObjectHashIterator { + + @SuppressWarnings("unchecked") + EntryIterator(THashMap map) { + super(map); + } + + + @SuppressWarnings({"unchecked"}) + public Entry objectAtIndex(final int index) { + return new Entry((K) _set[index], _values[index], index); + } + } + + + @SuppressWarnings({"unchecked"}) + public Iterator> iterator() { + return new EntryIterator(THashMap.this); + } + + + public boolean removeElement(Map.Entry entry) { + if (entry == null) return false; + + // have to effectively reimplement Map.remove here + // because we need to return true/false depending on + // whether the removal took place. Since the Entry's + // value can be null, this means that we can't rely + // on the value of the object returned by Map.remove() + // to determine whether a deletion actually happened. + // + // Note also that the deletion is only legal if + // both the key and the value match. + V val; + int index; + + K key = keyForEntry(entry); + index = index(key); + if (index >= 0) { + val = valueForEntry(entry); + if (val == _values[index] || + (null != val && THashMap.this.equals(val, _values[index]))) { + removeAt(index); // clear key,state; adjust size + return true; + } + } + return false; + } + + + public boolean containsElement(Map.Entry entry) { + V val = get(keyForEntry(entry)); + V entryValue = entry.getValue(); + return entryValue == val || + (null != val && THashMap.this.equals(val, entryValue)); + } + + + protected V valueForEntry(Map.Entry entry) { + return entry.getValue(); + } + + + protected K keyForEntry(Map.Entry entry) { + return entry.getKey(); + } + } + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + + public abstract boolean removeElement(E key); + + + public abstract boolean containsElement(E key); + + + @SuppressWarnings({"unchecked"}) + public boolean contains(Object key) { + return containsElement((E) key); + } + + + @SuppressWarnings({"unchecked"}) + public boolean remove(Object o) { + try { + return removeElement((E) o); + } catch (ClassCastException ex) { + return false; + } + } + + +// public boolean containsAll( Collection collection ) { +// for ( Object element : collection ) { +// if ( !contains( element ) ) { +// return false; +// } +// } +// return true; +// } + + + public void clear() { + THashMap.this.clear(); + } + + + public boolean add(E obj) { + throw new UnsupportedOperationException(); + } + + + public int size() { + return THashMap.this.size(); + } + + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for (int i = 0; e.hasNext(); i++) { + result[i] = e.next(); + } + return result; + } + + + @SuppressWarnings({"unchecked"}) + public T[] toArray(T[] a) { + int size = size(); + if (a.length < size) { + a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); + } + + Iterator it = iterator(); + Object[] result = a; + for (int i = 0; i < size; i++) { + result[i] = it.next(); + } + + if (a.length > size) { + a[size] = null; + } + + return a; + } + + + public boolean isEmpty() { + return THashMap.this.isEmpty(); + } + + + public boolean addAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + + public boolean retainAll(Collection collection) { + boolean changed = false; + Iterator i = iterator(); + while (i.hasNext()) { + if (!collection.contains(i.next())) { + i.remove(); + changed = true; + } + } + return changed; + } + + public String toString() { + Iterator i = iterator(); + if (!i.hasNext()) return "{}"; + + StringBuilder sb = new StringBuilder(); + sb.append('{'); + for (; ;) { + E e = i.next(); + sb.append(e == this ? "(this Collection)" : e); + if (!i.hasNext()) return sb.append('}').toString(); + sb.append(", "); + } + } + } + + /** + * a view onto the keys of the map. + */ + protected class KeyView extends MapBackedView { + + public Iterator iterator() { + return new TObjectHashIterator(THashMap.this); + } + + + public boolean removeElement(K key) { + return null != THashMap.this.remove(key); + } + + + public boolean containsElement(K key) { + return THashMap.this.contains(key); + } + } + + final class Entry implements Map.Entry { + + private K key; + private V val; + private final int index; + + + Entry(final K key, V value, final int index) { + this.key = key; + this.val = value; + this.index = index; + } + + + public K getKey() { + return key; + } + + + public V getValue() { + return val; + } + + + public V setValue(V o) { + if (_values[index] != val) { + throw new ConcurrentModificationException(); + } + // need to return previous value + V retval = val; + // update this entry's value, in case setValue is called again + _values[index] = o; + val = o; + return retval; + } + + + @SuppressWarnings("rawtypes") + public boolean equals(Object o) { + if (o instanceof Map.Entry) { + Map.Entry e1 = this; + Map.Entry e2 = (Map.Entry) o; + return (THashMap.this.equals(e1.getKey(), e2.getKey())) + && (THashMap.this.equals(e1.getValue(), e1.getValue())); + } + return false; + } + + + public int hashCode() { + return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode()); + } + + + @Override + public String toString() { + return key + "=" + val; + } + } + + + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(1); + + // NOTE: Super was not written in version 0 + super.writeExternal(out); + + // NUMBER OF ENTRIES + out.writeInt(_size); + + // ENTRIES + for (int i = _set.length; i-- > 0;) { + if (_set[i] != REMOVED && _set[i] != FREE) { + out.writeObject(_set[i]); + out.writeObject(_values[i]); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + byte version = in.readByte(); + + // NOTE: super was not written in version 0 + if (version != 0) { + super.readExternal(in); + } + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp(size); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = (K) in.readObject(); + //noinspection unchecked + V val = (V) in.readObject(); + put(key, val); + } + } +} // THashMap diff --git a/src/gnu/trove/map/hash/TIntByteHashMap.java b/src/gnu/trove/map/hash/TIntByteHashMap.java new file mode 100644 index 0000000..a395600 --- /dev/null +++ b/src/gnu/trove/map/hash/TIntByteHashMap.java @@ -0,0 +1,1298 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TIntByteMap; +import gnu.trove.function.TByteFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for int keys and byte values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TIntByteHashMap extends TIntByteHash implements TIntByteMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient byte[] _values; + + + /** + * Creates a new TIntByteHashMap instance with the default + * capacity and load factor. + */ + public TIntByteHashMap() { + super(); + } + + + /** + * Creates a new TIntByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntByteHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TIntByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a int value that represents + * null for the Key set. + * @param noEntryValue a byte value that represents + * null for the Value set. + */ + public TIntByteHashMap( int initialCapacity, float loadFactor, + int noEntryKey, byte noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TIntByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a int array containing the keys for the matching values. + * @param values a byte array containing the values. + */ + public TIntByteHashMap( int[] keys, byte[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TIntByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TIntByteMap that will be duplicated. + */ + public TIntByteHashMap( TIntByteMap map ) { + super( map.size() ); + if ( map instanceof TIntByteHashMap ) { + TIntByteHashMap hashmap = ( TIntByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + byte oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public byte put( int key, byte value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( int key, byte value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private byte doPut( int key, byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().intValue(), entry.getValue().byteValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TIntByteMap map ) { + ensureCapacity( map.size() ); + TIntByteIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public byte get( int key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public byte remove( int key ) { + byte prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TIntSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public int[] keys() { + int[] keys = new int[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public int[] keys( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + byte[] states = _states; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( int key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TIntByteIterator iterator() { + return new TIntByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TByteProcedure procedure ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TIntByteProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TIntByteProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + byte[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( int key ) { + return adjustValue( key, ( byte ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( int key, byte amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( int key, byte adjust_amount, byte put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TIntSet { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntByteKeyHashIterator( TIntByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntByteHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntByteHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntByteHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntByteMap + *

+ * {@inheritDoc} + */ + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + return no_entry_value != TIntByteHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntByteHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntByteHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntByteHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntByteHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TIntSet)) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TIntProcedure() { + private boolean first = true; + + + public boolean execute( int key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TIntByteValueHashIterator( TIntByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TIntByteHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TIntByteHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TIntByteHashMap.this.values( dest ); + } + + + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + int[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TIntByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TIntByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TIntByteHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TIntByteKeyHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntByteKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TIntByteValueHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntByteValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TIntByteHashIterator extends THashPrimitiveIterator implements TIntByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TIntByteHashMap we will be iterating over. + */ + TIntByteHashIterator( TIntByteHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public int key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntByteMap ) ) { + return false; + } + TIntByteMap that = ( TIntByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + byte[] values = _values; + byte[] states = _states; + byte this_no_entry_value = getNoEntryValue(); + byte that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + int key = _set[i]; + byte that_value = that.get( key ); + byte this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TIntByteProcedure() { + private boolean first = true; + public boolean execute( int key, byte value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + byte val = in.readByte(); + put(key, val); + } + } +} // TIntByteHashMap diff --git a/src/gnu/trove/map/hash/TIntCharHashMap.java b/src/gnu/trove/map/hash/TIntCharHashMap.java new file mode 100644 index 0000000..972a085 --- /dev/null +++ b/src/gnu/trove/map/hash/TIntCharHashMap.java @@ -0,0 +1,1300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TIntCharMap; +import gnu.trove.function.TCharFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for int keys and char values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TIntCharHashMap extends TIntCharHash implements TIntCharMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient char[] _values; + + + /** + * Creates a new TIntCharHashMap instance with the default + * capacity and load factor. + */ + public TIntCharHashMap() { + super(); + } + + + /** + * Creates a new TIntCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntCharHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TIntCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a int value that represents + * null for the Key set. + * @param noEntryValue a char value that represents + * null for the Value set. + */ + public TIntCharHashMap( int initialCapacity, float loadFactor, + int noEntryKey, char noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TIntCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a int array containing the keys for the matching values. + * @param values a char array containing the values. + */ + public TIntCharHashMap( int[] keys, char[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TIntCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TIntCharMap that will be duplicated. + */ + public TIntCharHashMap( TIntCharMap map ) { + super( map.size() ); + if ( map instanceof TIntCharHashMap ) { + TIntCharHashMap hashmap = ( TIntCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + char oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public char put( int key, char value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( int key, char value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private char doPut( int key, char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().intValue(), entry.getValue().charValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TIntCharMap map ) { + ensureCapacity( map.size() ); + TIntCharIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public char get( int key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public char remove( int key ) { + char prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TIntSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public int[] keys() { + int[] keys = new int[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public int[] keys( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + byte[] states = _states; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( int key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TIntCharIterator iterator() { + return new TIntCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TCharProcedure procedure ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TIntCharProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TIntCharProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + char[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( int key ) { + return adjustValue( key, ( char ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( int key, char amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( int key, char adjust_amount, char put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TIntSet { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntCharKeyHashIterator( TIntCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntCharHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntCharHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntCharHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntCharMap + *

+ * {@inheritDoc} + */ + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + return no_entry_value != TIntCharHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntCharHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntCharHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntCharHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntCharHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TIntSet)) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TIntProcedure() { + private boolean first = true; + + + public boolean execute( int key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TIntCharValueHashIterator( TIntCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TIntCharHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TIntCharHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TIntCharHashMap.this.values( dest ); + } + + + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + int[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TIntCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TIntCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TIntCharHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TIntCharKeyHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntCharKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TIntCharValueHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntCharValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TIntCharHashIterator extends THashPrimitiveIterator implements TIntCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TIntCharHashMap we will be iterating over. + */ + TIntCharHashIterator( TIntCharHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public int key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntCharMap ) ) { + return false; + } + TIntCharMap that = ( TIntCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + char[] values = _values; + byte[] states = _states; + char this_no_entry_value = getNoEntryValue(); + char that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + int key = _set[i]; + char that_value = that.get( key ); + char this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TIntCharProcedure() { + private boolean first = true; + public boolean execute( int key, char value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + char val = in.readChar(); + put(key, val); + } + } +} // TIntCharHashMap diff --git a/src/gnu/trove/map/hash/TIntDoubleHashMap.java b/src/gnu/trove/map/hash/TIntDoubleHashMap.java new file mode 100644 index 0000000..c63a29b --- /dev/null +++ b/src/gnu/trove/map/hash/TIntDoubleHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.TIntCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TIntDoubleHash; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TIntDoubleIterator; +import gnu.trove.iterator.TIntIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TIntDoubleMap; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TIntDoubleProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + +/** + * An open addressed Map implementation for int keys and double values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TIntDoubleHashMap extends TIntDoubleHash implements TIntDoubleMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient double[] _values; + + + /** + * Creates a new TIntDoubleHashMap instance with the default + * capacity and load factor. + */ + public TIntDoubleHashMap() { + super(); + } + + + /** + * Creates a new TIntDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TIntDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a int value that represents + * null for the Key set. + * @param noEntryValue a double value that represents + * null for the Value set. + */ + public TIntDoubleHashMap( int initialCapacity, float loadFactor, + int noEntryKey, double noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TIntDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a int array containing the keys for the matching values. + * @param values a double array containing the values. + */ + public TIntDoubleHashMap( int[] keys, double[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TIntDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TIntDoubleMap that will be duplicated. + */ + public TIntDoubleHashMap( TIntDoubleMap map ) { + super( map.size() ); + if ( map instanceof TIntDoubleHashMap ) { + TIntDoubleHashMap hashmap = ( TIntDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + double oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public double put( int key, double value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( int key, double value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private double doPut( int key, double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().intValue(), entry.getValue().doubleValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TIntDoubleMap map ) { + ensureCapacity( map.size() ); + TIntDoubleIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public double get( int key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public double remove( int key ) { + double prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TIntSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public int[] keys() { + int[] keys = new int[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public int[] keys( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + byte[] states = _states; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( int key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TIntDoubleIterator iterator() { + return new TIntDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TIntDoubleProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TIntDoubleProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + double[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( int key ) { + return adjustValue( key, ( double ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( int key, double amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( int key, double adjust_amount, double put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TIntSet { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntDoubleKeyHashIterator( TIntDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntDoubleHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntDoubleHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntDoubleHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntDoubleMap + *

+ * {@inheritDoc} + */ + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + return no_entry_value != TIntDoubleHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntDoubleHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntDoubleHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntDoubleHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntDoubleHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TIntSet)) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TIntProcedure() { + private boolean first = true; + + + public boolean execute( int key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TIntDoubleValueHashIterator( TIntDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TIntDoubleHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TIntDoubleHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TIntDoubleHashMap.this.values( dest ); + } + + + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + int[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TIntDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TIntDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TIntDoubleHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TIntDoubleKeyHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntDoubleKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TIntDoubleValueHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntDoubleValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TIntDoubleHashIterator extends THashPrimitiveIterator implements TIntDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TIntDoubleHashMap we will be iterating over. + */ + TIntDoubleHashIterator( TIntDoubleHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public int key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntDoubleMap ) ) { + return false; + } + TIntDoubleMap that = ( TIntDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + double[] values = _values; + byte[] states = _states; + double this_no_entry_value = getNoEntryValue(); + double that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + int key = _set[i]; + double that_value = that.get( key ); + double this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TIntDoubleProcedure() { + private boolean first = true; + public boolean execute( int key, double value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + double val = in.readDouble(); + put(key, val); + } + } +} // TIntDoubleHashMap diff --git a/src/gnu/trove/map/hash/TIntFloatHashMap.java b/src/gnu/trove/map/hash/TIntFloatHashMap.java new file mode 100644 index 0000000..949cd28 --- /dev/null +++ b/src/gnu/trove/map/hash/TIntFloatHashMap.java @@ -0,0 +1,1309 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TFloatCollection; +import gnu.trove.TIntCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TIntFloatHash; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TIntFloatIterator; +import gnu.trove.iterator.TIntIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TIntFloatMap; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TIntFloatProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + +/** + * An open addressed Map implementation for int keys and float values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TIntFloatHashMap extends TIntFloatHash implements TIntFloatMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient float[] _values; + + + /** + * Creates a new TIntFloatHashMap instance with the default + * capacity and load factor. + */ + public TIntFloatHashMap() { + super(); + } + + + /** + * Creates a new TIntFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TIntFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a int value that represents + * null for the Key set. + * @param noEntryValue a float value that represents + * null for the Value set. + */ + public TIntFloatHashMap( int initialCapacity, float loadFactor, + int noEntryKey, float noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TIntFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a int array containing the keys for the matching values. + * @param values a float array containing the values. + */ + public TIntFloatHashMap( int[] keys, float[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TIntFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TIntFloatMap that will be duplicated. + */ + public TIntFloatHashMap( TIntFloatMap map ) { + super( map.size() ); + if ( map instanceof TIntFloatHashMap ) { + TIntFloatHashMap hashmap = ( TIntFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + float oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public float put( int key, float value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( int key, float value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private float doPut( int key, float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().intValue(), entry.getValue().floatValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TIntFloatMap map ) { + ensureCapacity( map.size() ); + TIntFloatIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public float get( int key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public float remove( int key ) { + float prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TIntSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public int[] keys() { + int[] keys = new int[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public int[] keys( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + byte[] states = _states; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( int key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TIntFloatIterator iterator() { + return new TIntFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TFloatProcedure procedure ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TIntFloatProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TIntFloatProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + float[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( int key ) { + return adjustValue( key, ( float ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( int key, float amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( int key, float adjust_amount, float put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TIntSet { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntFloatKeyHashIterator( TIntFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntFloatHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntFloatHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntFloatHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntFloatMap + *

+ * {@inheritDoc} + */ + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + return no_entry_value != TIntFloatHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntFloatHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntFloatHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntFloatHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntFloatHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TIntSet)) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TIntProcedure() { + private boolean first = true; + + + public boolean execute( int key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TIntFloatValueHashIterator( TIntFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TIntFloatHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TIntFloatHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TIntFloatHashMap.this.values( dest ); + } + + + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + int[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TIntFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TIntFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TIntFloatHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TIntFloatKeyHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntFloatKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TIntFloatValueHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntFloatValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TIntFloatHashIterator extends THashPrimitiveIterator implements TIntFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TIntFloatHashMap we will be iterating over. + */ + TIntFloatHashIterator( TIntFloatHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public int key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntFloatMap ) ) { + return false; + } + TIntFloatMap that = ( TIntFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + float[] values = _values; + byte[] states = _states; + float this_no_entry_value = getNoEntryValue(); + float that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + int key = _set[i]; + float that_value = that.get( key ); + float this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TIntFloatProcedure() { + private boolean first = true; + public boolean execute( int key, float value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + float val = in.readFloat(); + put(key, val); + } + } +} // TIntFloatHashMap diff --git a/src/gnu/trove/map/hash/TIntIntHashMap.java b/src/gnu/trove/map/hash/TIntIntHashMap.java new file mode 100644 index 0000000..d0e79c6 --- /dev/null +++ b/src/gnu/trove/map/hash/TIntIntHashMap.java @@ -0,0 +1,1309 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TIntCollection; +import gnu.trove.function.TIntFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TIntIntHash; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TIntIntIterator; +import gnu.trove.iterator.TIntIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TIntIntMap; +import gnu.trove.procedure.TIntIntProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.set.TIntSet; + +/** + * An open addressed Map implementation for int keys and int values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TIntIntHashMap extends TIntIntHash implements TIntIntMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient int[] _values; + + + /** + * Creates a new TIntIntHashMap instance with the default + * capacity and load factor. + */ + public TIntIntHashMap() { + super(); + } + + + /** + * Creates a new TIntIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntIntHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TIntIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a int value that represents + * null for the Key set. + * @param noEntryValue a int value that represents + * null for the Value set. + */ + public TIntIntHashMap( int initialCapacity, float loadFactor, + int noEntryKey, int noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TIntIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a int array containing the keys for the matching values. + * @param values a int array containing the values. + */ + public TIntIntHashMap( int[] keys, int[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TIntIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TIntIntMap that will be duplicated. + */ + public TIntIntHashMap( TIntIntMap map ) { + super( map.size() ); + if ( map instanceof TIntIntHashMap ) { + TIntIntHashMap hashmap = ( TIntIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + int oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public int put( int key, int value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( int key, int value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private int doPut( int key, int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().intValue(), entry.getValue().intValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TIntIntMap map ) { + ensureCapacity( map.size() ); + TIntIntIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public int get( int key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public int remove( int key ) { + int prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TIntSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public int[] keys() { + int[] keys = new int[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public int[] keys( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + byte[] states = _states; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( int key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TIntIntIterator iterator() { + return new TIntIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TIntProcedure procedure ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TIntIntProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TIntIntProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + int[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( int key ) { + return adjustValue( key, ( int ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( int key, int amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( int key, int adjust_amount, int put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TIntSet { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntIntKeyHashIterator( TIntIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntIntHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntIntHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntIntHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntIntMap + *

+ * {@inheritDoc} + */ + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + return no_entry_value != TIntIntHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntIntHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntIntHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntIntHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntIntHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TIntSet)) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TIntProcedure() { + private boolean first = true; + + + public boolean execute( int key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntIntValueHashIterator( TIntIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntIntHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntIntHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntIntHashMap.this.values( dest ); + } + + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + int[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntIntHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TIntIntKeyHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntIntKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TIntIntValueHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntIntValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TIntIntHashIterator extends THashPrimitiveIterator implements TIntIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TIntIntHashMap we will be iterating over. + */ + TIntIntHashIterator( TIntIntHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public int key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntIntMap ) ) { + return false; + } + TIntIntMap that = ( TIntIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + int[] values = _values; + byte[] states = _states; + int this_no_entry_value = getNoEntryValue(); + int that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + int key = _set[i]; + int that_value = that.get( key ); + int this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TIntIntProcedure() { + private boolean first = true; + public boolean execute( int key, int value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + int val = in.readInt(); + put(key, val); + } + } +} // TIntIntHashMap diff --git a/src/gnu/trove/map/hash/TIntLongHashMap.java b/src/gnu/trove/map/hash/TIntLongHashMap.java new file mode 100644 index 0000000..6d373c3 --- /dev/null +++ b/src/gnu/trove/map/hash/TIntLongHashMap.java @@ -0,0 +1,1296 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TIntLongMap; +import gnu.trove.function.TLongFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for int keys and long values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TIntLongHashMap extends TIntLongHash implements TIntLongMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient long[] _values; + + + /** + * Creates a new TIntLongHashMap instance with the default + * capacity and load factor. + */ + public TIntLongHashMap() { + super(); + } + + + /** + * Creates a new TIntLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntLongHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TIntLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a int value that represents + * null for the Key set. + * @param noEntryValue a long value that represents + * null for the Value set. + */ + public TIntLongHashMap( int initialCapacity, float loadFactor, + int noEntryKey, long noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TIntLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a int array containing the keys for the matching values. + * @param values a long array containing the values. + */ + public TIntLongHashMap( int[] keys, long[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TIntLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TIntLongMap that will be duplicated. + */ + public TIntLongHashMap( TIntLongMap map ) { + super( map.size() ); + if ( map instanceof TIntLongHashMap ) { + TIntLongHashMap hashmap = ( TIntLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + long oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public long put( int key, long value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( int key, long value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private long doPut( int key, long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().intValue(), entry.getValue().longValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TIntLongMap map ) { + ensureCapacity( map.size() ); + TIntLongIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public long get( int key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public long remove( int key ) { + long prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TIntSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public int[] keys() { + int[] keys = new int[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public int[] keys( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + byte[] states = _states; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( int key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TIntLongIterator iterator() { + return new TIntLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TLongProcedure procedure ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TIntLongProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TIntLongProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + long[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( int key ) { + return adjustValue( key, ( long ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( int key, long amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( int key, long adjust_amount, long put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TIntSet { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntLongKeyHashIterator( TIntLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntLongHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntLongHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntLongHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntLongMap + *

+ * {@inheritDoc} + */ + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + return no_entry_value != TIntLongHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntLongHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntLongHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntLongHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntLongHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TIntSet)) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TIntProcedure() { + private boolean first = true; + + + public boolean execute( int key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TIntLongValueHashIterator( TIntLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TIntLongHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TIntLongHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TIntLongHashMap.this.values( dest ); + } + + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + int[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TIntLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TIntLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TIntLongHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TIntLongKeyHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntLongKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TIntLongValueHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntLongValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TIntLongHashIterator extends THashPrimitiveIterator implements TIntLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TIntLongHashMap we will be iterating over. + */ + TIntLongHashIterator( TIntLongHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public int key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntLongMap ) ) { + return false; + } + TIntLongMap that = ( TIntLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + long[] values = _values; + byte[] states = _states; + long this_no_entry_value = getNoEntryValue(); + long that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + int key = _set[i]; + long that_value = that.get( key ); + long this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TIntLongProcedure() { + private boolean first = true; + public boolean execute( int key, long value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + long val = in.readLong(); + put(key, val); + } + } +} // TIntLongHashMap diff --git a/src/gnu/trove/map/hash/TIntObjectHashMap.java b/src/gnu/trove/map/hash/TIntObjectHashMap.java new file mode 100644 index 0000000..b162fa3 --- /dev/null +++ b/src/gnu/trove/map/hash/TIntObjectHashMap.java @@ -0,0 +1,1028 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.map.TIntObjectMap; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.*; +import gnu.trove.procedure.TIntObjectProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.iterator.TIntObjectIterator; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TIntSet; +import gnu.trove.TIntCollection; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for int keys and Object values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TIntObjectHashMap extends TIntHash implements + TIntObjectMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TIntObjectProcedure PUT_ALL_PROC = new TIntObjectProcedure() { + public boolean execute( int key, V value) { + put( key, value ); + return true; + } + }; + + /** the values of the map */ + protected transient V[] _values; + + /** the value that represents null in the key set. */ + protected int no_entry_key; + + + /** + * Creates a new TIntObjectHashMap instance with the default + * capacity and load factor. + */ + public TIntObjectHashMap() { + super(); + } + + + /** + * Creates a new TIntObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntObjectHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TIntObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntObjectHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_key = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TIntObjectHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryKey the value used to represent null in the key set. + */ + public TIntObjectHashMap( int initialCapacity, float loadFactor, int noEntryKey ) { + super( initialCapacity, loadFactor ); + no_entry_key = noEntryKey; + } + + + /** + * Creates a new TIntObjectHashMap that contains the entries + * in the map passed to it. + * + * @param map the TIntObjectMap to be copied. + */ + public TIntObjectHashMap( TIntObjectMap map ) { + this( map.size(), 0.5f, map.getNoEntryKey() ); + putAll( map ); + } + + + + @SuppressWarnings({"unchecked"}) + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = ( V[] ) new Object[capacity]; + return capacity; + } + + + + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + V oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = (V[]) new Object[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey(o); + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + + public int getNoEntryKey() { + return no_entry_key; + } + + + + public boolean containsKey( int key ) { + return contains( key ); + } + + + + public boolean containsValue( Object val ) { + byte[] states = _states; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && null == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && + ( val == vals[i] || val.equals( vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + + public V get( int key ) { + int index = index( key ); + return index < 0 ? null : _values[index]; + } + + + // Modification Operations + + + public V put( int key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + + public V putIfAbsent( int key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + @SuppressWarnings({}) + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + + public V remove( int key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + + protected void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + + public void putAll( TIntObjectMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _states, 0, _states.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + // Views + + + public TIntSet keySet() { + return new KeyView(); + } + + + + @SuppressWarnings({}) + public int[] keys() { + int[] keys = new int[size()]; + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + + @SuppressWarnings({}) + public int[] keys( int[] dest ) { + if ( dest.length < _size ) { + dest = new int[_size]; + } + + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = k[i]; + } + } + return dest; + } + + + + public Collection valueCollection() { + return new ValueView(); + } + + + + @SuppressWarnings({}) + public Object[] values() { + Object[] vals = new Object[size()]; + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + + @SuppressWarnings({"unchecked"}) + public V[] values( V[] dest ) { + if ( dest.length < _size ) { + dest = ( V[] ) java.lang.reflect.Array.newInstance( + dest.getClass().getComponentType(), _size); + } + + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = ( V ) v[i]; + } + } + return dest; + } + + + + public TIntObjectIterator iterator() { + return new TIntObjectHashIterator( this ); + } + + + + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + + public boolean forEachValue( TObjectProcedure procedure ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + + @SuppressWarnings({}) + public boolean forEachEntry( TIntObjectProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (states[i] == FULL && ! procedure.execute(keys[i],values[i])) { + return false; + } + } + return true; + } + + + + @SuppressWarnings({}) + public boolean retainEntries( TIntObjectProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + + public void transformValues( TObjectFunction function ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntObjectMap ) ) { + return false; + } + TIntObjectMap that = ( TIntObjectMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TIntObjectIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + int key = iter.key(); + Object value = iter.value(); + if ( value == null ) { + if ( !( that.get( key ) == null && that.containsKey( key ) ) ) { + return false; + } + } else { + if ( !value.equals( that.get( key ) ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + + public int hashCode() { + int hashcode = 0; + V[] values = _values; + byte[] states = _states; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + ( values[i] == null ? 0 : values[i].hashCode() ); + } + } + return hashcode; + } + + + class KeyView implements TIntSet { + + + public int getNoEntryValue() { + return no_entry_key; + } + + + public int size() { + return _size; + } + + + public boolean isEmpty() { + return _size == 0; + } + + + public boolean contains( int entry ) { + return TIntObjectHashMap.this.containsKey( entry ); + } + + + public TIntIterator iterator() { + return new TIntHashIterator( TIntObjectHashMap.this ); + } + + + public int[] toArray() { + return keys(); + } + + + public int[] toArray( int[] dest ) { + return keys( dest ); + } + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + public boolean remove( int entry ) { + return null != TIntObjectHashMap.this.remove( entry ); + } + + + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( ! TIntObjectHashMap.this.containsKey( + ( ( Integer ) element ).intValue() ) ) { + + return false; + } + } + return true; + } + + + public boolean containsAll( TIntCollection collection ) { + if ( collection == this ) { + return true; + } + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntObjectHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntObjectHashMap.this.containsKey( element ) ) { + return false; + } + } + return true; + } + + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + //noinspection SuspiciousMethodCalls + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + public boolean removeAll( TIntCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + public void clear() { + TIntObjectHashMap.this.clear(); + } + + + public boolean forEach( TIntProcedure procedure ) { + return TIntObjectHashMap.this.forEachKey( procedure ); + } + + + public boolean equals( Object other ) { + if (! ( other instanceof TIntSet ) ) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( first ) first = false; + else buf.append( "," ); + buf.append( _set[i] ); + } + } + return buf.toString(); + } + + + class TIntHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** the collection on which the iterator operates */ + private final TIntHash _hash; + + + public TIntHashIterator( TIntHash hash ) { + super( hash ); + this._hash = hash; + } + + + public int next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({}) + public Iterator iterator() { + return new TIntObjectValueHashIterator( TIntObjectHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + public boolean removeElement( V value ) { + V[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + if ( value == values[i] || + ( null != values[i] && values[i].equals( value ) ) ) { + removeAt( i ); + return true; + } + } + } + return false; + } + + class TIntObjectValueHashIterator extends THashPrimitiveIterator + implements Iterator { + + @SuppressWarnings("rawtypes") + protected final TIntObjectHashMap _map; + + @SuppressWarnings("rawtypes") + public TIntObjectValueHashIterator( TIntObjectHashMap map ) { + super( map ); + _map = map; + } + + @SuppressWarnings("unchecked") + protected V objectAtIndex( int index ) { + byte[] states = _states; + Object value = _map._values[index]; + if ( states[index] != FULL ) { + return null; + } + return ( V ) value; + } + + + @SuppressWarnings("unchecked") + public V next() { + moveToNextIndex(); + return ( V ) _map._values[_index]; + } + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TIntObjectHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TIntObjectHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TIntObjectHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + @SuppressWarnings("hiding") + class TIntObjectHashIterator extends THashPrimitiveIterator + implements TIntObjectIterator { + + /** the collection being iterated over */ + private final TIntObjectHashMap _map; + + /** + * Creates an iterator over the specified map + * + * @param map map to iterate over. + */ + public TIntObjectHashIterator( TIntObjectHashMap map ) { + super( map ); + this._map = map; + } + + + public void advance() { + moveToNextIndex(); + } + + + public int key() { + return _map._set[_index]; + } + + + public V value() { + return _map._values[_index]; + } + + + public V setValue( V val ) { + V old = value(); + _map._values[_index] = val; + return old; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeInt( no_entry_key ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readInt(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + V val = (V) in.readObject(); + put(key, val); + } + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TIntObjectProcedure() { + private boolean first = true; + public boolean execute(int key, Object value) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } +} // TIntObjectHashMap diff --git a/src/gnu/trove/map/hash/TIntShortHashMap.java b/src/gnu/trove/map/hash/TIntShortHashMap.java new file mode 100644 index 0000000..fe2b5f4 --- /dev/null +++ b/src/gnu/trove/map/hash/TIntShortHashMap.java @@ -0,0 +1,1297 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TIntShortMap; +import gnu.trove.function.TShortFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for int keys and short values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TIntShortHashMap extends TIntShortHash implements TIntShortMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient short[] _values; + + + /** + * Creates a new TIntShortHashMap instance with the default + * capacity and load factor. + */ + public TIntShortHashMap() { + super(); + } + + + /** + * Creates a new TIntShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntShortHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TIntShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TIntShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a int value that represents + * null for the Key set. + * @param noEntryValue a short value that represents + * null for the Value set. + */ + public TIntShortHashMap( int initialCapacity, float loadFactor, + int noEntryKey, short noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TIntShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a int array containing the keys for the matching values. + * @param values a short array containing the values. + */ + public TIntShortHashMap( int[] keys, short[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TIntShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TIntShortMap that will be duplicated. + */ + public TIntShortHashMap( TIntShortMap map ) { + super( map.size() ); + if ( map instanceof TIntShortHashMap ) { + TIntShortHashMap hashmap = ( TIntShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldKeys[] = _set; + short oldVals[] = _values; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _values = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public short put( int key, short value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( int key, short value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private short doPut( int key, short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().intValue(), entry.getValue().shortValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TIntShortMap map ) { + ensureCapacity( map.size() ); + TIntShortIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public short get( int key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public short remove( int key ) { + short prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TIntSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public int[] keys() { + int[] keys = new int[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + int[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public int[] keys( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + byte[] states = _states; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( int key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TIntShortIterator iterator() { + return new TIntShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TIntProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TShortProcedure procedure ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TIntShortProcedure procedure ) { + byte[] states = _states; + int[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TIntShortProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + int[] keys = _set; + short[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( int key ) { + return adjustValue( key, ( short ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( int key, short amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( int key, short adjust_amount, short put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TIntSet { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntShortKeyHashIterator( TIntShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TIntShortHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TIntShortHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TIntShortHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntShortMap + *

+ * {@inheritDoc} + */ + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + return no_entry_value != TIntShortHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TIntShortHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntShortHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TIntShortHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TIntShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TIntShortHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TIntSet)) { + return false; + } + final TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TIntProcedure() { + private boolean first = true; + + + public boolean execute( int key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TIntShortValueHashIterator( TIntShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TIntShortHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TIntShortHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TIntShortHashMap.this.values( dest ); + } + + + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + int[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TIntShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TIntShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TIntShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TIntShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TIntShortHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TIntShortKeyHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntShortKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TIntShortValueHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TIntShortValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TIntShortHashIterator extends THashPrimitiveIterator implements TIntShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TIntShortHashMap we will be iterating over. + */ + TIntShortHashIterator( TIntShortHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public int key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TIntShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntShortMap ) ) { + return false; + } + TIntShortMap that = ( TIntShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + short[] values = _values; + byte[] states = _states; + short this_no_entry_value = getNoEntryValue(); + short that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + int key = _set[i]; + short that_value = that.get( key ); + short this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TIntShortProcedure() { + private boolean first = true; + public boolean execute( int key, short value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + int key = in.readInt(); + short val = in.readShort(); + put(key, val); + } + } +} // TIntShortHashMap diff --git a/src/gnu/trove/map/hash/TLongByteHashMap.java b/src/gnu/trove/map/hash/TLongByteHashMap.java new file mode 100644 index 0000000..c283ca2 --- /dev/null +++ b/src/gnu/trove/map/hash/TLongByteHashMap.java @@ -0,0 +1,1297 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TLongByteMap; +import gnu.trove.function.TByteFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for long keys and byte values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TLongByteHashMap extends TLongByteHash implements TLongByteMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient byte[] _values; + + + /** + * Creates a new TLongByteHashMap instance with the default + * capacity and load factor. + */ + public TLongByteHashMap() { + super(); + } + + + /** + * Creates a new TLongByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongByteHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TLongByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TLongByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a long value that represents + * null for the Key set. + * @param noEntryValue a byte value that represents + * null for the Value set. + */ + public TLongByteHashMap( int initialCapacity, float loadFactor, + long noEntryKey, byte noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TLongByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a long array containing the keys for the matching values. + * @param values a byte array containing the values. + */ + public TLongByteHashMap( long[] keys, byte[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TLongByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TLongByteMap that will be duplicated. + */ + public TLongByteHashMap( TLongByteMap map ) { + super( map.size() ); + if ( map instanceof TLongByteHashMap ) { + TLongByteHashMap hashmap = ( TLongByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + byte oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public byte put( long key, byte value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( long key, byte value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private byte doPut( long key, byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().longValue(), entry.getValue().byteValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TLongByteMap map ) { + ensureCapacity( map.size() ); + TLongByteIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public byte get( long key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public byte remove( long key ) { + byte prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TLongSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public long[] keys() { + long[] keys = new long[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public long[] keys( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + byte[] states = _states; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( long key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TLongByteIterator iterator() { + return new TLongByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TByteProcedure procedure ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TLongByteProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TLongByteProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + byte[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( long key ) { + return adjustValue( key, ( byte ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( long key, byte amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( long key, byte adjust_amount, byte put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TLongSet { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongByteKeyHashIterator( TLongByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongByteHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongByteHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongByteHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongByteMap + *

+ * {@inheritDoc} + */ + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + return no_entry_value != TLongByteHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongByteHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongByteHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongByteHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongByteHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TLongSet)) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TLongProcedure() { + private boolean first = true; + + + public boolean execute( long key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TLongByteValueHashIterator( TLongByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TLongByteHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TLongByteHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TLongByteHashMap.this.values( dest ); + } + + + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + long[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TLongByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TLongByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TLongByteHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TLongByteKeyHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongByteKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TLongByteValueHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongByteValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TLongByteHashIterator extends THashPrimitiveIterator implements TLongByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TLongByteHashMap we will be iterating over. + */ + TLongByteHashIterator( TLongByteHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public long key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongByteMap ) ) { + return false; + } + TLongByteMap that = ( TLongByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + byte[] values = _values; + byte[] states = _states; + byte this_no_entry_value = getNoEntryValue(); + byte that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + long key = _set[i]; + byte that_value = that.get( key ); + byte this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TLongByteProcedure() { + private boolean first = true; + public boolean execute( long key, byte value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + byte val = in.readByte(); + put(key, val); + } + } +} // TLongByteHashMap diff --git a/src/gnu/trove/map/hash/TLongCharHashMap.java b/src/gnu/trove/map/hash/TLongCharHashMap.java new file mode 100644 index 0000000..23638ee --- /dev/null +++ b/src/gnu/trove/map/hash/TLongCharHashMap.java @@ -0,0 +1,1300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TLongCharMap; +import gnu.trove.function.TCharFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for long keys and char values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TLongCharHashMap extends TLongCharHash implements TLongCharMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient char[] _values; + + + /** + * Creates a new TLongCharHashMap instance with the default + * capacity and load factor. + */ + public TLongCharHashMap() { + super(); + } + + + /** + * Creates a new TLongCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongCharHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TLongCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TLongCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a long value that represents + * null for the Key set. + * @param noEntryValue a char value that represents + * null for the Value set. + */ + public TLongCharHashMap( int initialCapacity, float loadFactor, + long noEntryKey, char noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TLongCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a long array containing the keys for the matching values. + * @param values a char array containing the values. + */ + public TLongCharHashMap( long[] keys, char[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TLongCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TLongCharMap that will be duplicated. + */ + public TLongCharHashMap( TLongCharMap map ) { + super( map.size() ); + if ( map instanceof TLongCharHashMap ) { + TLongCharHashMap hashmap = ( TLongCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + char oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public char put( long key, char value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( long key, char value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private char doPut( long key, char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().longValue(), entry.getValue().charValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TLongCharMap map ) { + ensureCapacity( map.size() ); + TLongCharIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public char get( long key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public char remove( long key ) { + char prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TLongSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public long[] keys() { + long[] keys = new long[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public long[] keys( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + byte[] states = _states; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( long key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TLongCharIterator iterator() { + return new TLongCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TCharProcedure procedure ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TLongCharProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TLongCharProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + char[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( long key ) { + return adjustValue( key, ( char ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( long key, char amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( long key, char adjust_amount, char put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TLongSet { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongCharKeyHashIterator( TLongCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongCharHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongCharHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongCharHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongCharMap + *

+ * {@inheritDoc} + */ + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + return no_entry_value != TLongCharHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongCharHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongCharHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongCharHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongCharHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TLongSet)) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TLongProcedure() { + private boolean first = true; + + + public boolean execute( long key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TLongCharValueHashIterator( TLongCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TLongCharHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TLongCharHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TLongCharHashMap.this.values( dest ); + } + + + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + long[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TLongCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TLongCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TLongCharHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TLongCharKeyHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongCharKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TLongCharValueHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongCharValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TLongCharHashIterator extends THashPrimitiveIterator implements TLongCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TLongCharHashMap we will be iterating over. + */ + TLongCharHashIterator( TLongCharHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public long key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongCharMap ) ) { + return false; + } + TLongCharMap that = ( TLongCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + char[] values = _values; + byte[] states = _states; + char this_no_entry_value = getNoEntryValue(); + char that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + long key = _set[i]; + char that_value = that.get( key ); + char this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TLongCharProcedure() { + private boolean first = true; + public boolean execute( long key, char value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + char val = in.readChar(); + put(key, val); + } + } +} // TLongCharHashMap diff --git a/src/gnu/trove/map/hash/TLongDoubleHashMap.java b/src/gnu/trove/map/hash/TLongDoubleHashMap.java new file mode 100644 index 0000000..b32ae99 --- /dev/null +++ b/src/gnu/trove/map/hash/TLongDoubleHashMap.java @@ -0,0 +1,1297 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TLongDoubleMap; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for long keys and double values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TLongDoubleHashMap extends TLongDoubleHash implements TLongDoubleMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient double[] _values; + + + /** + * Creates a new TLongDoubleHashMap instance with the default + * capacity and load factor. + */ + public TLongDoubleHashMap() { + super(); + } + + + /** + * Creates a new TLongDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TLongDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TLongDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a long value that represents + * null for the Key set. + * @param noEntryValue a double value that represents + * null for the Value set. + */ + public TLongDoubleHashMap( int initialCapacity, float loadFactor, + long noEntryKey, double noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TLongDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a long array containing the keys for the matching values. + * @param values a double array containing the values. + */ + public TLongDoubleHashMap( long[] keys, double[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TLongDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TLongDoubleMap that will be duplicated. + */ + public TLongDoubleHashMap( TLongDoubleMap map ) { + super( map.size() ); + if ( map instanceof TLongDoubleHashMap ) { + TLongDoubleHashMap hashmap = ( TLongDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + double oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public double put( long key, double value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( long key, double value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private double doPut( long key, double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().longValue(), entry.getValue().doubleValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TLongDoubleMap map ) { + ensureCapacity( map.size() ); + TLongDoubleIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public double get( long key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public double remove( long key ) { + double prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TLongSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public long[] keys() { + long[] keys = new long[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public long[] keys( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + byte[] states = _states; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( long key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TLongDoubleIterator iterator() { + return new TLongDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TLongDoubleProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TLongDoubleProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + double[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( long key ) { + return adjustValue( key, ( double ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( long key, double amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( long key, double adjust_amount, double put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TLongSet { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongDoubleKeyHashIterator( TLongDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongDoubleHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongDoubleHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongDoubleHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongDoubleMap + *

+ * {@inheritDoc} + */ + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + return no_entry_value != TLongDoubleHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongDoubleHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongDoubleHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongDoubleHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongDoubleHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TLongSet)) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TLongProcedure() { + private boolean first = true; + + + public boolean execute( long key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TLongDoubleValueHashIterator( TLongDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TLongDoubleHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TLongDoubleHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TLongDoubleHashMap.this.values( dest ); + } + + + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + long[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TLongDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TLongDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TLongDoubleHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TLongDoubleKeyHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongDoubleKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TLongDoubleValueHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongDoubleValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TLongDoubleHashIterator extends THashPrimitiveIterator implements TLongDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TLongDoubleHashMap we will be iterating over. + */ + TLongDoubleHashIterator( TLongDoubleHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public long key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongDoubleMap ) ) { + return false; + } + TLongDoubleMap that = ( TLongDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + double[] values = _values; + byte[] states = _states; + double this_no_entry_value = getNoEntryValue(); + double that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + long key = _set[i]; + double that_value = that.get( key ); + double this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TLongDoubleProcedure() { + private boolean first = true; + public boolean execute( long key, double value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + double val = in.readDouble(); + put(key, val); + } + } +} // TLongDoubleHashMap diff --git a/src/gnu/trove/map/hash/TLongFloatHashMap.java b/src/gnu/trove/map/hash/TLongFloatHashMap.java new file mode 100644 index 0000000..c8279a8 --- /dev/null +++ b/src/gnu/trove/map/hash/TLongFloatHashMap.java @@ -0,0 +1,1297 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TLongFloatMap; +import gnu.trove.function.TFloatFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for long keys and float values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TLongFloatHashMap extends TLongFloatHash implements TLongFloatMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient float[] _values; + + + /** + * Creates a new TLongFloatHashMap instance with the default + * capacity and load factor. + */ + public TLongFloatHashMap() { + super(); + } + + + /** + * Creates a new TLongFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TLongFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TLongFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a long value that represents + * null for the Key set. + * @param noEntryValue a float value that represents + * null for the Value set. + */ + public TLongFloatHashMap( int initialCapacity, float loadFactor, + long noEntryKey, float noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TLongFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a long array containing the keys for the matching values. + * @param values a float array containing the values. + */ + public TLongFloatHashMap( long[] keys, float[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TLongFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TLongFloatMap that will be duplicated. + */ + public TLongFloatHashMap( TLongFloatMap map ) { + super( map.size() ); + if ( map instanceof TLongFloatHashMap ) { + TLongFloatHashMap hashmap = ( TLongFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + float oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public float put( long key, float value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( long key, float value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private float doPut( long key, float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().longValue(), entry.getValue().floatValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TLongFloatMap map ) { + ensureCapacity( map.size() ); + TLongFloatIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public float get( long key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public float remove( long key ) { + float prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TLongSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public long[] keys() { + long[] keys = new long[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public long[] keys( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + byte[] states = _states; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( long key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TLongFloatIterator iterator() { + return new TLongFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TFloatProcedure procedure ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TLongFloatProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TLongFloatProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + float[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( long key ) { + return adjustValue( key, ( float ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( long key, float amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( long key, float adjust_amount, float put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TLongSet { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongFloatKeyHashIterator( TLongFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongFloatHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongFloatHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongFloatHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongFloatMap + *

+ * {@inheritDoc} + */ + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + return no_entry_value != TLongFloatHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongFloatHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongFloatHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongFloatHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongFloatHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TLongSet)) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TLongProcedure() { + private boolean first = true; + + + public boolean execute( long key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TLongFloatValueHashIterator( TLongFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TLongFloatHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TLongFloatHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TLongFloatHashMap.this.values( dest ); + } + + + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + long[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TLongFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TLongFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TLongFloatHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TLongFloatKeyHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongFloatKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TLongFloatValueHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongFloatValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TLongFloatHashIterator extends THashPrimitiveIterator implements TLongFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TLongFloatHashMap we will be iterating over. + */ + TLongFloatHashIterator( TLongFloatHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public long key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongFloatMap ) ) { + return false; + } + TLongFloatMap that = ( TLongFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + float[] values = _values; + byte[] states = _states; + float this_no_entry_value = getNoEntryValue(); + float that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + long key = _set[i]; + float that_value = that.get( key ); + float this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TLongFloatProcedure() { + private boolean first = true; + public boolean execute( long key, float value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + float val = in.readFloat(); + put(key, val); + } + } +} // TLongFloatHashMap diff --git a/src/gnu/trove/map/hash/TLongIntHashMap.java b/src/gnu/trove/map/hash/TLongIntHashMap.java new file mode 100644 index 0000000..2f05a6a --- /dev/null +++ b/src/gnu/trove/map/hash/TLongIntHashMap.java @@ -0,0 +1,1297 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TLongIntMap; +import gnu.trove.function.TIntFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for long keys and int values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TLongIntHashMap extends TLongIntHash implements TLongIntMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient int[] _values; + + + /** + * Creates a new TLongIntHashMap instance with the default + * capacity and load factor. + */ + public TLongIntHashMap() { + super(); + } + + + /** + * Creates a new TLongIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongIntHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TLongIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TLongIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a long value that represents + * null for the Key set. + * @param noEntryValue a int value that represents + * null for the Value set. + */ + public TLongIntHashMap( int initialCapacity, float loadFactor, + long noEntryKey, int noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TLongIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a long array containing the keys for the matching values. + * @param values a int array containing the values. + */ + public TLongIntHashMap( long[] keys, int[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TLongIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TLongIntMap that will be duplicated. + */ + public TLongIntHashMap( TLongIntMap map ) { + super( map.size() ); + if ( map instanceof TLongIntHashMap ) { + TLongIntHashMap hashmap = ( TLongIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + int oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public int put( long key, int value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( long key, int value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private int doPut( long key, int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().longValue(), entry.getValue().intValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TLongIntMap map ) { + ensureCapacity( map.size() ); + TLongIntIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public int get( long key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public int remove( long key ) { + int prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TLongSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public long[] keys() { + long[] keys = new long[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public long[] keys( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + byte[] states = _states; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( long key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TLongIntIterator iterator() { + return new TLongIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TIntProcedure procedure ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TLongIntProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TLongIntProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + int[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( long key ) { + return adjustValue( key, ( int ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( long key, int amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( long key, int adjust_amount, int put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TLongSet { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongIntKeyHashIterator( TLongIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongIntHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongIntHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongIntHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongIntMap + *

+ * {@inheritDoc} + */ + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + return no_entry_value != TLongIntHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongIntHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongIntHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongIntHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongIntHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TLongSet)) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TLongProcedure() { + private boolean first = true; + + + public boolean execute( long key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TLongIntValueHashIterator( TLongIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TLongIntHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TLongIntHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TLongIntHashMap.this.values( dest ); + } + + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + long[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TLongIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TLongIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TLongIntHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TLongIntKeyHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongIntKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TLongIntValueHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongIntValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TLongIntHashIterator extends THashPrimitiveIterator implements TLongIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TLongIntHashMap we will be iterating over. + */ + TLongIntHashIterator( TLongIntHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public long key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongIntMap ) ) { + return false; + } + TLongIntMap that = ( TLongIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + int[] values = _values; + byte[] states = _states; + int this_no_entry_value = getNoEntryValue(); + int that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + long key = _set[i]; + int that_value = that.get( key ); + int this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TLongIntProcedure() { + private boolean first = true; + public boolean execute( long key, int value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + int val = in.readInt(); + put(key, val); + } + } +} // TLongIntHashMap diff --git a/src/gnu/trove/map/hash/TLongLongHashMap.java b/src/gnu/trove/map/hash/TLongLongHashMap.java new file mode 100644 index 0000000..ef87306 --- /dev/null +++ b/src/gnu/trove/map/hash/TLongLongHashMap.java @@ -0,0 +1,1308 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TLongCollection; +import gnu.trove.function.TLongFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TLongLongHash; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.iterator.TLongLongIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TLongLongMap; +import gnu.trove.procedure.TLongLongProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.set.TLongSet; + +/** + * An open addressed Map implementation for long keys and long values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TLongLongHashMap extends TLongLongHash implements TLongLongMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient long[] _values; + + + /** + * Creates a new TLongLongHashMap instance with the default + * capacity and load factor. + */ + public TLongLongHashMap() { + super(); + } + + + /** + * Creates a new TLongLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongLongHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TLongLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TLongLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a long value that represents + * null for the Key set. + * @param noEntryValue a long value that represents + * null for the Value set. + */ + public TLongLongHashMap( int initialCapacity, float loadFactor, + long noEntryKey, long noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TLongLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a long array containing the keys for the matching values. + * @param values a long array containing the values. + */ + public TLongLongHashMap( long[] keys, long[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TLongLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TLongLongMap that will be duplicated. + */ + public TLongLongHashMap( TLongLongMap map ) { + super( map.size() ); + if ( map instanceof TLongLongHashMap ) { + TLongLongHashMap hashmap = ( TLongLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + long oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public long put( long key, long value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( long key, long value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private long doPut( long key, long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().longValue(), entry.getValue().longValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TLongLongMap map ) { + ensureCapacity( map.size() ); + TLongLongIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public long get( long key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public long remove( long key ) { + long prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TLongSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public long[] keys() { + long[] keys = new long[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public long[] keys( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + byte[] states = _states; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( long key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TLongLongIterator iterator() { + return new TLongLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TLongProcedure procedure ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TLongLongProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TLongLongProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + long[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( long key ) { + return adjustValue( key, ( long ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( long key, long amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( long key, long adjust_amount, long put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TLongSet { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongLongKeyHashIterator( TLongLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongLongHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongLongHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongLongHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongLongMap + *

+ * {@inheritDoc} + */ + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + return no_entry_value != TLongLongHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongLongHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongLongHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongLongHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongLongHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TLongSet)) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TLongProcedure() { + private boolean first = true; + + + public boolean execute( long key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongLongValueHashIterator( TLongLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongLongHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongLongHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongLongHashMap.this.values( dest ); + } + + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + long[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongLongHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TLongLongKeyHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongLongKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TLongLongValueHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongLongValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TLongLongHashIterator extends THashPrimitiveIterator implements TLongLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TLongLongHashMap we will be iterating over. + */ + TLongLongHashIterator( TLongLongHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public long key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongLongMap ) ) { + return false; + } + TLongLongMap that = ( TLongLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + long[] values = _values; + byte[] states = _states; + long this_no_entry_value = getNoEntryValue(); + long that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + long key = _set[i]; + long that_value = that.get( key ); + long this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TLongLongProcedure() { + private boolean first = true; + public boolean execute( long key, long value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + long val = in.readLong(); + put(key, val); + } + } +} // TLongLongHashMap diff --git a/src/gnu/trove/map/hash/TLongObjectHashMap.java b/src/gnu/trove/map/hash/TLongObjectHashMap.java new file mode 100644 index 0000000..7270529 --- /dev/null +++ b/src/gnu/trove/map/hash/TLongObjectHashMap.java @@ -0,0 +1,1030 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.map.TLongObjectMap; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.*; +import gnu.trove.procedure.TLongObjectProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.iterator.TLongObjectIterator; +import gnu.trove.iterator.TPrimitiveIterator; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TLongSet; +import gnu.trove.TLongCollection; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for long keys and Object values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +@SuppressWarnings("unused") +public class TLongObjectHashMap extends TLongHash implements + TLongObjectMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TLongObjectProcedure PUT_ALL_PROC = new TLongObjectProcedure() { + public boolean execute( long key, V value) { + put( key, value ); + return true; + } + }; + + /** the values of the map */ + protected transient V[] _values; + + /** the value that represents null in the key set. */ + protected long no_entry_key; + + + /** + * Creates a new TLongObjectHashMap instance with the default + * capacity and load factor. + */ + public TLongObjectHashMap() { + super(); + } + + + /** + * Creates a new TLongObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongObjectHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TLongObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongObjectHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_key = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TLongObjectHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryKey the value used to represent null in the key set. + */ + public TLongObjectHashMap( int initialCapacity, float loadFactor, long noEntryKey ) { + super( initialCapacity, loadFactor ); + no_entry_key = noEntryKey; + } + + + /** + * Creates a new TLongObjectHashMap that contains the entries + * in the map passed to it. + * + * @param map the TLongObjectMap to be copied. + */ + public TLongObjectHashMap( TLongObjectMap map ) { + this( map.size(), 0.5f, map.getNoEntryKey() ); + putAll( map ); + } + + + + @SuppressWarnings({"unchecked"}) + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = ( V[] ) new Object[capacity]; + return capacity; + } + + + + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + V oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = (V[]) new Object[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey(o); + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + + public long getNoEntryKey() { + return no_entry_key; + } + + + + public boolean containsKey( long key ) { + return contains( key ); + } + + + + public boolean containsValue( Object val ) { + byte[] states = _states; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && null == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && + ( val == vals[i] || val.equals( vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + + public V get( long key ) { + int index = index( key ); + return index < 0 ? null : _values[index]; + } + + + // Modification Operations + + + public V put( long key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + + public V putIfAbsent( long key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + @SuppressWarnings({}) + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + + public V remove( long key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + + protected void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + + public void putAll( TLongObjectMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _states, 0, _states.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + // Views + + + public TLongSet keySet() { + return new KeyView(); + } + + + + @SuppressWarnings({}) + public long[] keys() { + long[] keys = new long[size()]; + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + + @SuppressWarnings({}) + public long[] keys( long[] dest ) { + if ( dest.length < _size ) { + dest = new long[_size]; + } + + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = k[i]; + } + } + return dest; + } + + + + public Collection valueCollection() { + return new ValueView(); + } + + + + @SuppressWarnings({}) + public Object[] values() { + Object[] vals = new Object[size()]; + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + + @SuppressWarnings({"unchecked"}) + public V[] values( V[] dest ) { + if ( dest.length < _size ) { + dest = ( V[] ) java.lang.reflect.Array.newInstance( + dest.getClass().getComponentType(), _size); + } + + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = ( V ) v[i]; + } + } + return dest; + } + + + + public TLongObjectIterator iterator() { + return new TLongObjectHashIterator( this ); + } + + + + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + + public boolean forEachValue( TObjectProcedure procedure ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + + @SuppressWarnings({}) + public boolean forEachEntry( TLongObjectProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (states[i] == FULL && ! procedure.execute(keys[i],values[i])) { + return false; + } + } + return true; + } + + + + @SuppressWarnings({}) + public boolean retainEntries( TLongObjectProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + + public void transformValues( TObjectFunction function ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongObjectMap ) ) { + return false; + } + TLongObjectMap that = ( TLongObjectMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TLongObjectIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + long key = iter.key(); + Object value = iter.value(); + if ( value == null ) { + if ( !( that.get( key ) == null && that.containsKey( key ) ) ) { + return false; + } + } else { + if ( !value.equals( that.get( key ) ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + + public int hashCode() { + int hashcode = 0; + V[] values = _values; + byte[] states = _states; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + ( values[i] == null ? 0 : values[i].hashCode() ); + } + } + return hashcode; + } + + + class KeyView implements TLongSet { + + + public long getNoEntryValue() { + return no_entry_key; + } + + + public int size() { + return _size; + } + + + public boolean isEmpty() { + return _size == 0; + } + + + public boolean contains( long entry ) { + return TLongObjectHashMap.this.containsKey( entry ); + } + + + public TLongIterator iterator() { + return new TLongHashIterator( TLongObjectHashMap.this ); + } + + + public long[] toArray() { + return keys(); + } + + + public long[] toArray( long[] dest ) { + return keys( dest ); + } + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + public boolean remove( long entry ) { + return null != TLongObjectHashMap.this.remove( entry ); + } + + + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( ! TLongObjectHashMap.this.containsKey( + ( ( Long ) element ).longValue() ) ) { + + return false; + } + } + return true; + } + + + public boolean containsAll( TLongCollection collection ) { + if ( collection == this ) { + return true; + } + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongObjectHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongObjectHashMap.this.containsKey( element ) ) { + return false; + } + } + return true; + } + + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + //noinspection SuspiciousMethodCalls + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + public boolean removeAll( TLongCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + public void clear() { + TLongObjectHashMap.this.clear(); + } + + + public boolean forEach( TLongProcedure procedure ) { + return TLongObjectHashMap.this.forEachKey( procedure ); + } + + + public boolean equals( Object other ) { + if (! ( other instanceof TLongSet ) ) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( first ) first = false; + else buf.append( "," ); + buf.append( _set[i] ); + } + } + return buf.toString(); + } + + + class TLongHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** the collection on which the iterator operates */ + private final TLongHash _hash; + + + public TLongHashIterator( TLongHash hash ) { + super( hash ); + this._hash = hash; + } + + + public long next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({}) + public Iterator iterator() { + return new TLongObjectValueHashIterator( TLongObjectHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + public boolean removeElement( V value ) { + V[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + if ( value == values[i] || + ( null != values[i] && values[i].equals( value ) ) ) { + removeAt( i ); + return true; + } + } + } + return false; + } + + class TLongObjectValueHashIterator extends THashPrimitiveIterator + implements Iterator { + + @SuppressWarnings("rawtypes") + protected final TLongObjectHashMap _map; + + @SuppressWarnings("rawtypes") + public TLongObjectValueHashIterator( TLongObjectHashMap map ) { + super( map ); + _map = map; + } + + @SuppressWarnings("unchecked") + protected V objectAtIndex( int index ) { + byte[] states = _states; + Object value = _map._values[index]; + if ( states[index] != FULL ) { + return null; + } + return ( V ) value; + } + + + @SuppressWarnings("unchecked") + public V next() { + moveToNextIndex(); + return ( V ) _map._values[_index]; + } + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TLongObjectHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TLongObjectHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TLongObjectHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + @SuppressWarnings("hiding") + class TLongObjectHashIterator extends THashPrimitiveIterator + implements TLongObjectIterator { + + /** the collection being iterated over */ + private final TLongObjectHashMap _map; + + /** + * Creates an iterator over the specified map + * + * @param map map to iterate over. + */ + public TLongObjectHashIterator( TLongObjectHashMap map ) { + super( map ); + this._map = map; + } + + + public void advance() { + moveToNextIndex(); + } + + + public long key() { + return _map._set[_index]; + } + + + public V value() { + return _map._values[_index]; + } + + + public V setValue( V val ) { + V old = value(); + _map._values[_index] = val; + return old; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeLong( no_entry_key ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readLong(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + V val = (V) in.readObject(); + put(key, val); + } + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TLongObjectProcedure() { + private boolean first = true; + public boolean execute(long key, Object value) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } +} // TLongObjectHashMap diff --git a/src/gnu/trove/map/hash/TLongShortHashMap.java b/src/gnu/trove/map/hash/TLongShortHashMap.java new file mode 100644 index 0000000..6f805a0 --- /dev/null +++ b/src/gnu/trove/map/hash/TLongShortHashMap.java @@ -0,0 +1,1311 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TLongCollection; +import gnu.trove.TShortCollection; +import gnu.trove.function.TShortFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TLongShortHash; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.iterator.TLongShortIterator; +import gnu.trove.iterator.TShortIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TLongShortMap; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.procedure.TLongShortProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TLongSet; + +/** + * An open addressed Map implementation for long keys and short values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TLongShortHashMap extends TLongShortHash implements TLongShortMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient short[] _values; + + + /** + * Creates a new TLongShortHashMap instance with the default + * capacity and load factor. + */ + public TLongShortHashMap() { + super(); + } + + + /** + * Creates a new TLongShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongShortHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TLongShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLongShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TLongShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a long value that represents + * null for the Key set. + * @param noEntryValue a short value that represents + * null for the Value set. + */ + public TLongShortHashMap( int initialCapacity, float loadFactor, + long noEntryKey, short noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TLongShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a long array containing the keys for the matching values. + * @param values a short array containing the values. + */ + public TLongShortHashMap( long[] keys, short[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TLongShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TLongShortMap that will be duplicated. + */ + public TLongShortHashMap( TLongShortMap map ) { + super( map.size() ); + if ( map instanceof TLongShortHashMap ) { + TLongShortHashMap hashmap = ( TLongShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldKeys[] = _set; + short oldVals[] = _values; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _values = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public short put( long key, short value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( long key, short value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private short doPut( long key, short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().longValue(), entry.getValue().shortValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TLongShortMap map ) { + ensureCapacity( map.size() ); + TLongShortIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public short get( long key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public short remove( long key ) { + short prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TLongSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public long[] keys() { + long[] keys = new long[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + long[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public long[] keys( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + byte[] states = _states; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( long key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TLongShortIterator iterator() { + return new TLongShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TLongProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TShortProcedure procedure ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TLongShortProcedure procedure ) { + byte[] states = _states; + long[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TLongShortProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + long[] keys = _set; + short[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( long key ) { + return adjustValue( key, ( short ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( long key, short amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( long key, short adjust_amount, short put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TLongSet { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongShortKeyHashIterator( TLongShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TLongShortHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TLongShortHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TLongShortHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongShortMap + *

+ * {@inheritDoc} + */ + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + return no_entry_value != TLongShortHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TLongShortHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongShortHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TLongShortHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TLongShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TLongShortHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TLongSet)) { + return false; + } + final TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TLongProcedure() { + private boolean first = true; + + + public boolean execute( long key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TLongShortValueHashIterator( TLongShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TLongShortHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TLongShortHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TLongShortHashMap.this.values( dest ); + } + + + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + long[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TLongShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TLongShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TLongShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TLongShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TLongShortHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TLongShortKeyHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongShortKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TLongShortValueHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TLongShortValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TLongShortHashIterator extends THashPrimitiveIterator implements TLongShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TLongShortHashMap we will be iterating over. + */ + TLongShortHashIterator( TLongShortHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public long key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TLongShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongShortMap ) ) { + return false; + } + TLongShortMap that = ( TLongShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + short[] values = _values; + byte[] states = _states; + short this_no_entry_value = getNoEntryValue(); + short that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + long key = _set[i]; + short that_value = that.get( key ); + short this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TLongShortProcedure() { + private boolean first = true; + public boolean execute( long key, short value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + long key = in.readLong(); + short val = in.readShort(); + put(key, val); + } + } +} // TLongShortHashMap diff --git a/src/gnu/trove/map/hash/TObjectByteHashMap.java b/src/gnu/trove/map/hash/TObjectByteHashMap.java new file mode 100644 index 0000000..a916899 --- /dev/null +++ b/src/gnu/trove/map/hash/TObjectByteHashMap.java @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THash; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.procedure.TObjectByteProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TByteProcedure; +import gnu.trove.iterator.TObjectByteIterator; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.function.TByteFunction; +import gnu.trove.map.TObjectByteMap; +import gnu.trove.TByteCollection; + + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and byte values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TObjectByteHashMap extends TObjectHash + implements TObjectByteMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectByteProcedure PUT_ALL_PROC = new TObjectByteProcedure() { + public boolean execute(K key, byte value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient byte[] _values; + + /** the value that represents null */ + protected byte no_entry_value; + + + /** + * Creates a new TObjectByteHashMap instance with the default + * capacity and load factor. + */ + public TObjectByteHashMap() { + super(); + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectByteHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_value = Constants.DEFAULT_BYTE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectByteHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectByteHashMap( int initialCapacity, float loadFactor, byte noEntryValue ) { + super( initialCapacity, loadFactor ); + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectByteHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectByteMap to be copied. + */ + @SuppressWarnings("rawtypes") + public TObjectByteHashMap( TObjectByteMap map ) { + this( map.size(), 0.5f, map.getNoEntryValue() ); + if ( map instanceof TObjectByteHashMap ) { + TObjectByteHashMap hashmap = ( TObjectByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + byte oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new byte[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldKeys[i] != FREE && oldKeys[i] != REMOVED ) { + K o = oldKeys[i]; + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _set[index] = o; + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + Object[] keys = _set; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public byte get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public byte put( K key, byte value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( K key, byte value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private byte doPut( byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public byte remove( Object key ) { + byte prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectByteMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TByteValueCollection(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + byte[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectByteIterator iterator() { + return new TObjectByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (byte)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, byte amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( final K key, final byte adjust_amount, + final byte put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TByteProcedure procedure ) { + Object[] keys = _set; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectByteProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectByteProcedure procedure ) { + Object[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectByteProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + byte[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TByteFunction value + */ + public void transformValues( TByteFunction function ) { + Object[] keys = _set; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectByteMap ) ) { + return false; + } + TObjectByteMap that = ( TObjectByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectByteIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + byte value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectByteHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectByteHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectByteHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectByteHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectByteHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectByteHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TByteValueCollection implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TObjectByteValueHashIterator(); + } + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TObjectByteHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public byte[] toArray() { + return TObjectByteHashMap.this.values(); + } + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TObjectByteHashMap.this.values( dest ); + } + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TObjectByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TObjectByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectByteHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TObjectByteHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectByteValueHashIterator implements TByteIterator { + + protected THash _hash = TObjectByteHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectByteValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectByteHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || + set[i] == TObjectHash.REMOVED ) ) { + + // do nothing + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectByteHashIterator extends TObjectHashIterator + implements TObjectByteIterator { + + /** the collection being iterated over */ + private final TObjectByteHashMap _map; + + public TObjectByteHashIterator( TObjectByteHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_VALUE + out.writeByte( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_VALUE + no_entry_value = in.readByte(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + byte val = in.readByte(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectByteProcedure() { + private boolean first = true; + public boolean execute( K key, byte value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} // TObjectByteHashMap diff --git a/src/gnu/trove/map/hash/TObjectCharHashMap.java b/src/gnu/trove/map/hash/TObjectCharHashMap.java new file mode 100644 index 0000000..cf1238c --- /dev/null +++ b/src/gnu/trove/map/hash/TObjectCharHashMap.java @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THash; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.procedure.TObjectCharProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TCharProcedure; +import gnu.trove.iterator.TObjectCharIterator; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.function.TCharFunction; +import gnu.trove.map.TObjectCharMap; +import gnu.trove.TCharCollection; + + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and char values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TObjectCharHashMap extends TObjectHash + implements TObjectCharMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectCharProcedure PUT_ALL_PROC = new TObjectCharProcedure() { + public boolean execute(K key, char value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient char[] _values; + + /** the value that represents null */ + protected char no_entry_value; + + + /** + * Creates a new TObjectCharHashMap instance with the default + * capacity and load factor. + */ + public TObjectCharHashMap() { + super(); + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectCharHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_value = Constants.DEFAULT_CHAR_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectCharHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectCharHashMap( int initialCapacity, float loadFactor, char noEntryValue ) { + super( initialCapacity, loadFactor ); + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectCharHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectCharMap to be copied. + */ + @SuppressWarnings("rawtypes") + public TObjectCharHashMap( TObjectCharMap map ) { + this( map.size(), 0.5f, map.getNoEntryValue() ); + if ( map instanceof TObjectCharHashMap ) { + TObjectCharHashMap hashmap = ( TObjectCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + char oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new char[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldKeys[i] != FREE && oldKeys[i] != REMOVED ) { + K o = oldKeys[i]; + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _set[index] = o; + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + Object[] keys = _set; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public char get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public char put( K key, char value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( K key, char value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private char doPut( char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public char remove( Object key ) { + char prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectCharMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TCharValueCollection(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + char[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectCharIterator iterator() { + return new TObjectCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (char)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, char amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( final K key, final char adjust_amount, + final char put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TCharProcedure procedure ) { + Object[] keys = _set; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectCharProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectCharProcedure procedure ) { + Object[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectCharProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + char[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TCharFunction value + */ + public void transformValues( TCharFunction function ) { + Object[] keys = _set; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectCharMap ) ) { + return false; + } + TObjectCharMap that = ( TObjectCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectCharIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + char value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectCharHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectCharHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectCharHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectCharHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectCharHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectCharHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TCharValueCollection implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TObjectCharValueHashIterator(); + } + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TObjectCharHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public char[] toArray() { + return TObjectCharHashMap.this.values(); + } + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TObjectCharHashMap.this.values( dest ); + } + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TObjectCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TObjectCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectCharHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TObjectCharHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectCharValueHashIterator implements TCharIterator { + + protected THash _hash = TObjectCharHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectCharValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectCharHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || + set[i] == TObjectHash.REMOVED ) ) { + + // do nothing + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectCharHashIterator extends TObjectHashIterator + implements TObjectCharIterator { + + /** the collection being iterated over */ + private final TObjectCharHashMap _map; + + public TObjectCharHashIterator( TObjectCharHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_VALUE + out.writeChar( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_VALUE + no_entry_value = in.readChar(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + char val = in.readChar(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectCharProcedure() { + private boolean first = true; + public boolean execute( K key, char value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} // TObjectCharHashMap diff --git a/src/gnu/trove/map/hash/TObjectDoubleHashMap.java b/src/gnu/trove/map/hash/TObjectDoubleHashMap.java new file mode 100644 index 0000000..76b4af1 --- /dev/null +++ b/src/gnu/trove/map/hash/TObjectDoubleHashMap.java @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THash; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.procedure.TObjectDoubleProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.iterator.TObjectDoubleIterator; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.map.TObjectDoubleMap; +import gnu.trove.TDoubleCollection; + + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and double values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TObjectDoubleHashMap extends TObjectHash + implements TObjectDoubleMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectDoubleProcedure PUT_ALL_PROC = new TObjectDoubleProcedure() { + public boolean execute(K key, double value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient double[] _values; + + /** the value that represents null */ + protected double no_entry_value; + + + /** + * Creates a new TObjectDoubleHashMap instance with the default + * capacity and load factor. + */ + public TObjectDoubleHashMap() { + super(); + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_value = Constants.DEFAULT_DOUBLE_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectDoubleHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectDoubleHashMap( int initialCapacity, float loadFactor, double noEntryValue ) { + super( initialCapacity, loadFactor ); + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectDoubleHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectDoubleMap to be copied. + */ + @SuppressWarnings("rawtypes") + public TObjectDoubleHashMap( TObjectDoubleMap map ) { + this( map.size(), 0.5f, map.getNoEntryValue() ); + if ( map instanceof TObjectDoubleHashMap ) { + TObjectDoubleHashMap hashmap = ( TObjectDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + double oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new double[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldKeys[i] != FREE && oldKeys[i] != REMOVED ) { + K o = oldKeys[i]; + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _set[index] = o; + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + Object[] keys = _set; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public double get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public double put( K key, double value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( K key, double value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private double doPut( double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public double remove( Object key ) { + double prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectDoubleMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TDoubleValueCollection(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + double[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectDoubleIterator iterator() { + return new TObjectDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (double)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, double amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( final K key, final double adjust_amount, + final double put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TDoubleProcedure procedure ) { + Object[] keys = _set; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectDoubleProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectDoubleProcedure procedure ) { + Object[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectDoubleProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + double[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TDoubleFunction value + */ + public void transformValues( TDoubleFunction function ) { + Object[] keys = _set; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectDoubleMap ) ) { + return false; + } + TObjectDoubleMap that = ( TObjectDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectDoubleIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + double value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectDoubleHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectDoubleHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectDoubleHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectDoubleHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectDoubleHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectDoubleHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TDoubleValueCollection implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TObjectDoubleValueHashIterator(); + } + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TObjectDoubleHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public double[] toArray() { + return TObjectDoubleHashMap.this.values(); + } + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TObjectDoubleHashMap.this.values( dest ); + } + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TObjectDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TObjectDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectDoubleHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TObjectDoubleHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectDoubleValueHashIterator implements TDoubleIterator { + + protected THash _hash = TObjectDoubleHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectDoubleValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectDoubleHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || + set[i] == TObjectHash.REMOVED ) ) { + + // do nothing + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectDoubleHashIterator extends TObjectHashIterator + implements TObjectDoubleIterator { + + /** the collection being iterated over */ + private final TObjectDoubleHashMap _map; + + public TObjectDoubleHashIterator( TObjectDoubleHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_VALUE + out.writeDouble( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_VALUE + no_entry_value = in.readDouble(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + double val = in.readDouble(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectDoubleProcedure() { + private boolean first = true; + public boolean execute( K key, double value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} // TObjectDoubleHashMap diff --git a/src/gnu/trove/map/hash/TObjectFloatHashMap.java b/src/gnu/trove/map/hash/TObjectFloatHashMap.java new file mode 100644 index 0000000..1df2d84 --- /dev/null +++ b/src/gnu/trove/map/hash/TObjectFloatHashMap.java @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THash; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.procedure.TObjectFloatProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.iterator.TObjectFloatIterator; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.function.TFloatFunction; +import gnu.trove.map.TObjectFloatMap; +import gnu.trove.TFloatCollection; + + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and float values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TObjectFloatHashMap extends TObjectHash + implements TObjectFloatMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectFloatProcedure PUT_ALL_PROC = new TObjectFloatProcedure() { + public boolean execute(K key, float value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient float[] _values; + + /** the value that represents null */ + protected float no_entry_value; + + + /** + * Creates a new TObjectFloatHashMap instance with the default + * capacity and load factor. + */ + public TObjectFloatHashMap() { + super(); + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectFloatHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectFloatHashMap( int initialCapacity, float loadFactor, float noEntryValue ) { + super( initialCapacity, loadFactor ); + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectFloatHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectFloatMap to be copied. + */ + @SuppressWarnings("rawtypes") + public TObjectFloatHashMap( TObjectFloatMap map ) { + this( map.size(), 0.5f, map.getNoEntryValue() ); + if ( map instanceof TObjectFloatHashMap ) { + TObjectFloatHashMap hashmap = ( TObjectFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + float oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new float[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldKeys[i] != FREE && oldKeys[i] != REMOVED ) { + K o = oldKeys[i]; + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _set[index] = o; + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + Object[] keys = _set; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public float get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public float put( K key, float value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( K key, float value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private float doPut( float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public float remove( Object key ) { + float prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectFloatMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TFloatValueCollection(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + float[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectFloatIterator iterator() { + return new TObjectFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (float)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, float amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( final K key, final float adjust_amount, + final float put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TFloatProcedure procedure ) { + Object[] keys = _set; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectFloatProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectFloatProcedure procedure ) { + Object[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectFloatProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + float[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TFloatFunction value + */ + public void transformValues( TFloatFunction function ) { + Object[] keys = _set; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectFloatMap ) ) { + return false; + } + TObjectFloatMap that = ( TObjectFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectFloatIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + float value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectFloatHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectFloatHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectFloatHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectFloatHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectFloatHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectFloatHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TFloatValueCollection implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TObjectFloatValueHashIterator(); + } + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TObjectFloatHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public float[] toArray() { + return TObjectFloatHashMap.this.values(); + } + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TObjectFloatHashMap.this.values( dest ); + } + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TObjectFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TObjectFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectFloatHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TObjectFloatHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectFloatValueHashIterator implements TFloatIterator { + + protected THash _hash = TObjectFloatHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectFloatValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectFloatHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || + set[i] == TObjectHash.REMOVED ) ) { + + // do nothing + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectFloatHashIterator extends TObjectHashIterator + implements TObjectFloatIterator { + + /** the collection being iterated over */ + private final TObjectFloatHashMap _map; + + public TObjectFloatHashIterator( TObjectFloatHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_VALUE + out.writeFloat( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_VALUE + no_entry_value = in.readFloat(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + float val = in.readFloat(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectFloatProcedure() { + private boolean first = true; + public boolean execute( K key, float value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} // TObjectFloatHashMap diff --git a/src/gnu/trove/map/hash/TObjectIntHashMap.java b/src/gnu/trove/map/hash/TObjectIntHashMap.java new file mode 100644 index 0000000..652f9c4 --- /dev/null +++ b/src/gnu/trove/map/hash/TObjectIntHashMap.java @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THash; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.procedure.TObjectIntProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.iterator.TObjectIntIterator; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.function.TIntFunction; +import gnu.trove.map.TObjectIntMap; +import gnu.trove.TIntCollection; + + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and int values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TObjectIntHashMap extends TObjectHash + implements TObjectIntMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectIntProcedure PUT_ALL_PROC = new TObjectIntProcedure() { + public boolean execute(K key, int value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient int[] _values; + + /** the value that represents null */ + protected int no_entry_value; + + + /** + * Creates a new TObjectIntHashMap instance with the default + * capacity and load factor. + */ + public TObjectIntHashMap() { + super(); + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectIntHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectIntHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectIntHashMap( int initialCapacity, float loadFactor, int noEntryValue ) { + super( initialCapacity, loadFactor ); + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectIntHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectIntMap to be copied. + */ + @SuppressWarnings("rawtypes") + public TObjectIntHashMap( TObjectIntMap map ) { + this( map.size(), 0.5f, map.getNoEntryValue() ); + if ( map instanceof TObjectIntHashMap ) { + TObjectIntHashMap hashmap = ( TObjectIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + int oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new int[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldKeys[i] != FREE && oldKeys[i] != REMOVED ) { + K o = oldKeys[i]; + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _set[index] = o; + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + Object[] keys = _set; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public int get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public int put( K key, int value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( K key, int value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private int doPut( int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public int remove( Object key ) { + int prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectIntMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TIntValueCollection(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + int[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectIntIterator iterator() { + return new TObjectIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (int)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, int amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( final K key, final int adjust_amount, + final int put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TIntProcedure procedure ) { + Object[] keys = _set; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectIntProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectIntProcedure procedure ) { + Object[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectIntProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + int[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TIntFunction value + */ + public void transformValues( TIntFunction function ) { + Object[] keys = _set; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectIntMap ) ) { + return false; + } + TObjectIntMap that = ( TObjectIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectIntIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + int value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectIntHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectIntHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectIntHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectIntHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectIntHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectIntHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TIntValueCollection implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TObjectIntValueHashIterator(); + } + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TObjectIntHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public int[] toArray() { + return TObjectIntHashMap.this.values(); + } + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TObjectIntHashMap.this.values( dest ); + } + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TObjectIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TObjectIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectIntHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TObjectIntHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectIntValueHashIterator implements TIntIterator { + + protected THash _hash = TObjectIntHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectIntValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectIntHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || + set[i] == TObjectHash.REMOVED ) ) { + + // do nothing + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectIntHashIterator extends TObjectHashIterator + implements TObjectIntIterator { + + /** the collection being iterated over */ + private final TObjectIntHashMap _map; + + public TObjectIntHashIterator( TObjectIntHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_VALUE + out.writeInt( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_VALUE + no_entry_value = in.readInt(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + int val = in.readInt(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectIntProcedure() { + private boolean first = true; + public boolean execute( K key, int value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} // TObjectIntHashMap diff --git a/src/gnu/trove/map/hash/TObjectLongHashMap.java b/src/gnu/trove/map/hash/TObjectLongHashMap.java new file mode 100644 index 0000000..1fda3de --- /dev/null +++ b/src/gnu/trove/map/hash/TObjectLongHashMap.java @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THash; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.procedure.TObjectLongProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TLongProcedure; +import gnu.trove.iterator.TObjectLongIterator; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.function.TLongFunction; +import gnu.trove.map.TObjectLongMap; +import gnu.trove.TLongCollection; + + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and long values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TObjectLongHashMap extends TObjectHash + implements TObjectLongMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectLongProcedure PUT_ALL_PROC = new TObjectLongProcedure() { + public boolean execute(K key, long value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient long[] _values; + + /** the value that represents null */ + protected long no_entry_value; + + + /** + * Creates a new TObjectLongHashMap instance with the default + * capacity and load factor. + */ + public TObjectLongHashMap() { + super(); + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectLongHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectLongHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectLongHashMap( int initialCapacity, float loadFactor, long noEntryValue ) { + super( initialCapacity, loadFactor ); + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectLongHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectLongMap to be copied. + */ + @SuppressWarnings("rawtypes") + public TObjectLongHashMap( TObjectLongMap map ) { + this( map.size(), 0.5f, map.getNoEntryValue() ); + if ( map instanceof TObjectLongHashMap ) { + TObjectLongHashMap hashmap = ( TObjectLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + long oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new long[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldKeys[i] != FREE && oldKeys[i] != REMOVED ) { + K o = oldKeys[i]; + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _set[index] = o; + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + Object[] keys = _set; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public long get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public long put( K key, long value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( K key, long value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private long doPut( long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public long remove( Object key ) { + long prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectLongMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TLongValueCollection(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + long[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectLongIterator iterator() { + return new TObjectLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (long)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, long amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( final K key, final long adjust_amount, + final long put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TLongProcedure procedure ) { + Object[] keys = _set; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectLongProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectLongProcedure procedure ) { + Object[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectLongProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + long[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TLongFunction value + */ + public void transformValues( TLongFunction function ) { + Object[] keys = _set; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectLongMap ) ) { + return false; + } + TObjectLongMap that = ( TObjectLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectLongIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + long value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectLongHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectLongHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectLongHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectLongHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectLongHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectLongHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TLongValueCollection implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TObjectLongValueHashIterator(); + } + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TObjectLongHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public long[] toArray() { + return TObjectLongHashMap.this.values(); + } + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TObjectLongHashMap.this.values( dest ); + } + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TObjectLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TObjectLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectLongHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TObjectLongHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectLongValueHashIterator implements TLongIterator { + + protected THash _hash = TObjectLongHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectLongValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectLongHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || + set[i] == TObjectHash.REMOVED ) ) { + + // do nothing + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectLongHashIterator extends TObjectHashIterator + implements TObjectLongIterator { + + /** the collection being iterated over */ + private final TObjectLongHashMap _map; + + public TObjectLongHashIterator( TObjectLongHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_VALUE + out.writeLong( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_VALUE + no_entry_value = in.readLong(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + long val = in.readLong(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectLongProcedure() { + private boolean first = true; + public boolean execute( K key, long value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} // TObjectLongHashMap diff --git a/src/gnu/trove/map/hash/TObjectShortHashMap.java b/src/gnu/trove/map/hash/TObjectShortHashMap.java new file mode 100644 index 0000000..f96ccff --- /dev/null +++ b/src/gnu/trove/map/hash/TObjectShortHashMap.java @@ -0,0 +1,1154 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THash; +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.procedure.TObjectShortProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.iterator.TObjectShortIterator; +import gnu.trove.iterator.TShortIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.function.TShortFunction; +import gnu.trove.map.TObjectShortMap; +import gnu.trove.TShortCollection; + + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for Object keys and short values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +public class TObjectShortHashMap extends TObjectHash + implements TObjectShortMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TObjectShortProcedure PUT_ALL_PROC = new TObjectShortProcedure() { + public boolean execute(K key, short value) { + put(key, value); + return true; + } + }; + + /** the values of the map */ + protected transient short[] _values; + + /** the value that represents null */ + protected short no_entry_value; + + + /** + * Creates a new TObjectShortHashMap instance with the default + * capacity and load factor. + */ + public TObjectShortHashMap() { + super(); + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TObjectShortHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TObjectShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_value = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TObjectShortHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryValue the value used to represent null. + */ + public TObjectShortHashMap( int initialCapacity, float loadFactor, short noEntryValue ) { + super( initialCapacity, loadFactor ); + no_entry_value = noEntryValue; + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, no_entry_value ); + } + } + + + /** + * Creates a new TObjectShortHashMap that contains the entries + * in the map passed to it. + * + * @param map the TObjectShortMap to be copied. + */ + @SuppressWarnings("rawtypes") + public TObjectShortHashMap( TObjectShortMap map ) { + this( map.size(), 0.5f, map.getNoEntryValue() ); + if ( map instanceof TObjectShortHashMap ) { + TObjectShortHashMap hashmap = ( TObjectShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + public int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + //noinspection unchecked + K oldKeys[] = ( K[] ) _set; + short oldVals[] = _values; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + _values = new short[newCapacity]; + Arrays.fill( _values, no_entry_value ); + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldKeys[i] != FREE && oldKeys[i] != REMOVED ) { + K o = oldKeys[i]; + int index = insertKey(o); + if ( index < 0 ) { + throwObjectContractViolation( _set[ (-index -1) ], o); + } + _set[index] = o; + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public boolean containsKey( Object key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + Object[] keys = _set; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public short get( Object key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public short put( K key, short value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( K key, short value ) { + int index = insertKey(key); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + private short doPut( short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + //noinspection unchecked + _values[index] = value; + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + return previous; + } + + + /** {@inheritDoc} */ + public short remove( Object key ) { + short prev = no_entry_value; + int index = index(key); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** + * Removes the mapping at index from the map. + * This method is used internally and public mainly because + * of packaging reasons. Caveat Programmer. + * + * @param index an int value + */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TObjectShortMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, FREE ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + } + + + // Views + + /** {@inheritDoc} */ + public Set keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public Object[] keys() { + //noinspection unchecked + K[] keys = ( K[] ) new Object[size()]; + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + keys[j++] = ( K ) k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public K[] keys( K[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = ( K[] ) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Object[] k = _set; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( k[i] != FREE && k[i] != REMOVED ) { + //noinspection unchecked + a[j++] = ( K ) k[i]; + } + } + return a; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TShortValueCollection(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + short[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + Object[] keys = _set; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + array[j++] = v[i]; + } + } + if ( array.length > size ) { + array[size] = no_entry_value; + } + return array; + } + + + /** + * @return an iterator over the entries in this map + */ + public TObjectShortIterator iterator() { + return new TObjectShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean increment( K key ) { + //noinspection RedundantCast + return adjustValue( key, (short)1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( K key, short amount ) { + int index = index(key); + if ( index < 0 ) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( final K key, final short adjust_amount, + final short put_amount ) { + + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + //noinspection unchecked + + if ( isNewMapping ) { + postInsertHook( consumeFreeSlot ); + } + + return newValue; + } + + + /** + * Executes procedure for each key in the map. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the keys terminated because + * the procedure returned false for some key. + */ + public boolean forEachKey( TObjectProcedure procedure ) { + return forEach( procedure ); + } + + + /** + * Executes procedure for each value in the map. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the values terminated because + * the procedure returned false for some value. + */ + public boolean forEachValue( TShortProcedure procedure ) { + Object[] keys = _set; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED + && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Executes procedure for each key/value entry in the + * map. + * + * @param procedure a TOObjectShortProcedure value + * @return false if the loop over the entries terminated because + * the procedure returned false for some entry. + */ + @SuppressWarnings({"unchecked"}) + public boolean forEachEntry( TObjectShortProcedure procedure ) { + Object[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( ( K ) keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** + * Retains only those entries in the map for which the procedure + * returns a true value. + * + * @param procedure determines which entries to keep + * @return true if the map was modified. + */ + @SuppressWarnings("unchecked") + public boolean retainEntries( TObjectShortProcedure procedure ) { + boolean modified = false; + //noinspection unchecked + K[] keys = ( K[] ) _set; + short[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( keys[i] != FREE + && keys[i] != REMOVED + && ! procedure.execute( keys[i], values[i] ) ) { + removeAt(i); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** + * Transform the values in this map using function. + * + * @param function a TShortFunction value + */ + public void transformValues( TShortFunction function ) { + Object[] keys = _set; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != null && keys[i] != REMOVED ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** + * Compares this map with another map for equality of their stored + * entries. + * + * @param other an Object value + * @return a boolean value + */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TObjectShortMap ) ) { + return false; + } + TObjectShortMap that = ( TObjectShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TObjectShortIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + Object key = iter.key(); + short value = iter.value(); + if ( value == no_entry_value ) { + if ( !( that.get( key ) == that.getNoEntryValue() && + that.containsKey( key ) ) ) { + + return false; + } + } else { + if ( value != that.get( key ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + Object[] keys = _set; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( keys[i] != FREE && keys[i] != REMOVED ) { + hashcode += HashFunctions.hash( values[i] ) ^ + ( keys[i] == null ? 0 : keys[i].hashCode() ); + } + } + return hashcode; + } + + + /** a view onto the keys of the map. */ + protected class KeyView extends MapBackedView { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public Iterator iterator() { + return new TObjectHashIterator( TObjectShortHashMap.this ); + } + + public boolean removeElement( K key ) { + return no_entry_value != TObjectShortHashMap.this.remove( key ); + } + + public boolean containsElement( K key ) { + return TObjectShortHashMap.this.contains( key ); + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TObjectShortHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TObjectShortHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + //noinspection unchecked + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TObjectShortHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + class TShortValueCollection implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TObjectShortValueHashIterator(); + } + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TObjectShortHashMap.this.containsValue( entry ); + } + + /** {@inheritDoc} */ + public short[] toArray() { + return TObjectShortHashMap.this.values(); + } + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TObjectShortHashMap.this.values( dest ); + } + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + Object[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TObjectShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TObjectShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TObjectShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + + Object[] set = _set; + for ( int i = set.length; i-- > 0; ) { + if ( set[i] != FREE + && set[i] != REMOVED + && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TObjectShortHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TObjectShortHashMap.this.forEachValue( procedure ); + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + class TObjectShortValueHashIterator implements TShortIterator { + + protected THash _hash = TObjectShortHashMap.this; + + /** + * the number of elements this iterator believes are in the + * data structure it accesses. + */ + protected int _expectedSize; + + /** the index used for iteration. */ + protected int _index; + + /** Creates an iterator over the specified map */ + TObjectShortValueHashIterator() { + _expectedSize = _hash.size(); + _index = _hash.capacity(); + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return nextIndex() >= 0; + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for + // bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TObjectShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + + /** + * Sets the internal index so that the `next' object + * can be returned. + */ + protected final void moveToNextIndex() { + // doing the assignment && < 0 in one line shaves + // 3 opcodes... + if ( ( _index = nextIndex() ) < 0 ) { + throw new NoSuchElementException(); + } + } + + /** + * Returns the index of the next value in the data structure + * or a negative value if the iterator is exhausted. + * + * @return an int value + * @throws ConcurrentModificationException + * if the underlying + * collection's size has been modified since the iterator was + * created. + */ + protected final int nextIndex() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + Object[] set = TObjectShortHashMap.this._set; + int i = _index; + while ( i-- > 0 && ( set[i] == TObjectHash.FREE || + set[i] == TObjectHash.REMOVED ) ) { + + // do nothing + } + return i; + } + } + } + + + @SuppressWarnings("hiding") + class TObjectShortHashIterator extends TObjectHashIterator + implements TObjectShortIterator { + + /** the collection being iterated over */ + private final TObjectShortHashMap _map; + + public TObjectShortHashIterator( TObjectShortHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public K key() { + return ( K ) _map._set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _map._values[_index] = val; + return old; + } + } + + + // Externalization + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_VALUE + out.writeShort( no_entry_value ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + @SuppressWarnings("unchecked") + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_VALUE + no_entry_value = in.readShort(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + //noinspection unchecked + K key = ( K ) in.readObject(); + short val = in.readShort(); + put(key, val); + } + } + + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry( new TObjectShortProcedure() { + private boolean first = true; + public boolean execute( K key, short value ) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append( key ).append( "=" ).append( value ); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } +} // TObjectShortHashMap diff --git a/src/gnu/trove/map/hash/TShortByteHashMap.java b/src/gnu/trove/map/hash/TShortByteHashMap.java new file mode 100644 index 0000000..ac7cecc --- /dev/null +++ b/src/gnu/trove/map/hash/TShortByteHashMap.java @@ -0,0 +1,1300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TShortByteMap; +import gnu.trove.function.TByteFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for short keys and byte values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TShortByteHashMap extends TShortByteHash implements TShortByteMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient byte[] _values; + + + /** + * Creates a new TShortByteHashMap instance with the default + * capacity and load factor. + */ + public TShortByteHashMap() { + super(); + } + + + /** + * Creates a new TShortByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortByteHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TShortByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortByteHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TShortByteHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a short value that represents + * null for the Key set. + * @param noEntryValue a byte value that represents + * null for the Value set. + */ + public TShortByteHashMap( int initialCapacity, float loadFactor, + short noEntryKey, byte noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TShortByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a short array containing the keys for the matching values. + * @param values a byte array containing the values. + */ + public TShortByteHashMap( short[] keys, byte[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TShortByteHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TShortByteMap that will be duplicated. + */ + public TShortByteHashMap( TShortByteMap map ) { + super( map.size() ); + if ( map instanceof TShortByteHashMap ) { + TShortByteHashMap hashmap = ( TShortByteHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new byte[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + byte oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public byte put( short key, byte value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public byte putIfAbsent( short key, byte value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private byte doPut( short key, byte value, int index ) { + byte previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().shortValue(), entry.getValue().byteValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortByteMap map ) { + ensureCapacity( map.size() ); + TShortByteIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public byte get( short key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public byte remove( short key ) { + byte prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public short[] keys() { + short[] keys = new short[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public short[] keys( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TByteCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public byte[] values() { + byte[] vals = new byte[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public byte[] values( byte[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new byte[size]; + } + + byte[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( byte val ) { + byte[] states = _states; + byte[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TShortByteIterator iterator() { + return new TShortByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TByteProcedure procedure ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TShortByteProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + byte[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TByteFunction function ) { + byte[] states = _states; + byte[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TShortByteProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + byte[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( short key ) { + return adjustValue( key, ( byte ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( short key, byte amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public byte adjustOrPutValue( short key, byte adjust_amount, byte put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final byte newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TShortSet { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortByteKeyHashIterator( TShortByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortByteHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortByteHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortByteHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortByteMap + *

+ * {@inheritDoc} + */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return no_entry_value != TShortByteHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortByteHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortByteHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortByteHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortByteMap + *

+ * {@inheritDoc} + */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortByteHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TShortSet)) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TShortProcedure() { + private boolean first = true; + + + public boolean execute( short key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TByteCollection { + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TShortByteValueHashIterator( TShortByteHashMap.this ); + } + + + /** {@inheritDoc} */ + public byte getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( byte entry ) { + return TShortByteHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + return TShortByteHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + return TShortByteHashMap.this.values( dest ); + } + + + + public boolean add( byte entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( byte entry ) { + byte[] values = _values; + short[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte ele = ( ( Byte ) element ).byteValue(); + if ( ! TShortByteHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortByteHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( byte element : array ) { + if ( ! TShortByteHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortByteHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TByteProcedure procedure ) { + return TShortByteHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TByteProcedure() { + private boolean first = true; + + public boolean execute( byte value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TShortByteKeyHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortByteKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TShortByteValueHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortByteValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TShortByteHashIterator extends THashPrimitiveIterator implements TShortByteIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TShortByteHashMap we will be iterating over. + */ + TShortByteHashIterator( TShortByteHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public byte value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public byte setValue( byte val ) { + byte old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortByteHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortByteMap ) ) { + return false; + } + TShortByteMap that = ( TShortByteMap ) other; + if ( that.size() != this.size() ) { + return false; + } + byte[] values = _values; + byte[] states = _states; + byte this_no_entry_value = getNoEntryValue(); + byte that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + short key = _set[i]; + byte that_value = that.get( key ); + byte this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TShortByteProcedure() { + private boolean first = true; + public boolean execute( short key, byte value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeByte( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + byte val = in.readByte(); + put(key, val); + } + } +} // TShortByteHashMap diff --git a/src/gnu/trove/map/hash/TShortCharHashMap.java b/src/gnu/trove/map/hash/TShortCharHashMap.java new file mode 100644 index 0000000..78d6bff --- /dev/null +++ b/src/gnu/trove/map/hash/TShortCharHashMap.java @@ -0,0 +1,1300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TShortCharMap; +import gnu.trove.function.TCharFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for short keys and char values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TShortCharHashMap extends TShortCharHash implements TShortCharMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient char[] _values; + + + /** + * Creates a new TShortCharHashMap instance with the default + * capacity and load factor. + */ + public TShortCharHashMap() { + super(); + } + + + /** + * Creates a new TShortCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortCharHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TShortCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortCharHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TShortCharHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a short value that represents + * null for the Key set. + * @param noEntryValue a char value that represents + * null for the Value set. + */ + public TShortCharHashMap( int initialCapacity, float loadFactor, + short noEntryKey, char noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TShortCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a short array containing the keys for the matching values. + * @param values a char array containing the values. + */ + public TShortCharHashMap( short[] keys, char[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TShortCharHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TShortCharMap that will be duplicated. + */ + public TShortCharHashMap( TShortCharMap map ) { + super( map.size() ); + if ( map instanceof TShortCharHashMap ) { + TShortCharHashMap hashmap = ( TShortCharHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new char[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + char oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public char put( short key, char value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public char putIfAbsent( short key, char value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private char doPut( short key, char value, int index ) { + char previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().shortValue(), entry.getValue().charValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortCharMap map ) { + ensureCapacity( map.size() ); + TShortCharIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public char get( short key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public char remove( short key ) { + char prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public short[] keys() { + short[] keys = new short[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public short[] keys( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TCharCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public char[] values() { + char[] vals = new char[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public char[] values( char[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new char[size]; + } + + char[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( char val ) { + byte[] states = _states; + char[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TShortCharIterator iterator() { + return new TShortCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TCharProcedure procedure ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TShortCharProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + char[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TCharFunction function ) { + byte[] states = _states; + char[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TShortCharProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + char[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( short key ) { + return adjustValue( key, ( char ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( short key, char amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public char adjustOrPutValue( short key, char adjust_amount, char put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final char newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TShortSet { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortCharKeyHashIterator( TShortCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortCharHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortCharHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortCharHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortCharMap + *

+ * {@inheritDoc} + */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return no_entry_value != TShortCharHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortCharHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortCharHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortCharHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortCharMap + *

+ * {@inheritDoc} + */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortCharHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TShortSet)) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TShortProcedure() { + private boolean first = true; + + + public boolean execute( short key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TCharCollection { + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TShortCharValueHashIterator( TShortCharHashMap.this ); + } + + + /** {@inheritDoc} */ + public char getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( char entry ) { + return TShortCharHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + return TShortCharHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + return TShortCharHashMap.this.values( dest ); + } + + + + public boolean add( char entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( char entry ) { + char[] values = _values; + short[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char ele = ( ( Character ) element ).charValue(); + if ( ! TShortCharHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortCharHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( char element : array ) { + if ( ! TShortCharHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortCharHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TCharProcedure procedure ) { + return TShortCharHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TCharProcedure() { + private boolean first = true; + + public boolean execute( char value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TShortCharKeyHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortCharKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TShortCharValueHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortCharValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TShortCharHashIterator extends THashPrimitiveIterator implements TShortCharIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TShortCharHashMap we will be iterating over. + */ + TShortCharHashIterator( TShortCharHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public char value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public char setValue( char val ) { + char old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortCharHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortCharMap ) ) { + return false; + } + TShortCharMap that = ( TShortCharMap ) other; + if ( that.size() != this.size() ) { + return false; + } + char[] values = _values; + byte[] states = _states; + char this_no_entry_value = getNoEntryValue(); + char that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + short key = _set[i]; + char that_value = that.get( key ); + char this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TShortCharProcedure() { + private boolean first = true; + public boolean execute( short key, char value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeChar( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + char val = in.readChar(); + put(key, val); + } + } +} // TShortCharHashMap diff --git a/src/gnu/trove/map/hash/TShortDoubleHashMap.java b/src/gnu/trove/map/hash/TShortDoubleHashMap.java new file mode 100644 index 0000000..96ce8ad --- /dev/null +++ b/src/gnu/trove/map/hash/TShortDoubleHashMap.java @@ -0,0 +1,1310 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TDoubleCollection; +import gnu.trove.TShortCollection; +import gnu.trove.function.TDoubleFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.impl.hash.TShortDoubleHash; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.iterator.TShortDoubleIterator; +import gnu.trove.iterator.TShortIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TShortDoubleMap; +import gnu.trove.procedure.TDoubleProcedure; +import gnu.trove.procedure.TShortDoubleProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + +/** + * An open addressed Map implementation for short keys and double values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TShortDoubleHashMap extends TShortDoubleHash implements TShortDoubleMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient double[] _values; + + + /** + * Creates a new TShortDoubleHashMap instance with the default + * capacity and load factor. + */ + public TShortDoubleHashMap() { + super(); + } + + + /** + * Creates a new TShortDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortDoubleHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TShortDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortDoubleHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TShortDoubleHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a short value that represents + * null for the Key set. + * @param noEntryValue a double value that represents + * null for the Value set. + */ + public TShortDoubleHashMap( int initialCapacity, float loadFactor, + short noEntryKey, double noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TShortDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a short array containing the keys for the matching values. + * @param values a double array containing the values. + */ + public TShortDoubleHashMap( short[] keys, double[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TShortDoubleHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TShortDoubleMap that will be duplicated. + */ + public TShortDoubleHashMap( TShortDoubleMap map ) { + super( map.size() ); + if ( map instanceof TShortDoubleHashMap ) { + TShortDoubleHashMap hashmap = ( TShortDoubleHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new double[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + double oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public double put( short key, double value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public double putIfAbsent( short key, double value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private double doPut( short key, double value, int index ) { + double previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().shortValue(), entry.getValue().doubleValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortDoubleMap map ) { + ensureCapacity( map.size() ); + TShortDoubleIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public double get( short key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public double remove( short key ) { + double prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public short[] keys() { + short[] keys = new short[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public short[] keys( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TDoubleCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public double[] values() { + double[] vals = new double[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public double[] values( double[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new double[size]; + } + + double[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( double val ) { + byte[] states = _states; + double[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TShortDoubleIterator iterator() { + return new TShortDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TDoubleProcedure procedure ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TShortDoubleProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + double[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TDoubleFunction function ) { + byte[] states = _states; + double[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TShortDoubleProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + double[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( short key ) { + return adjustValue( key, ( double ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( short key, double amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public double adjustOrPutValue( short key, double adjust_amount, double put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final double newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TShortSet { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortDoubleKeyHashIterator( TShortDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortDoubleHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortDoubleHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortDoubleHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortDoubleMap + *

+ * {@inheritDoc} + */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return no_entry_value != TShortDoubleHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortDoubleHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortDoubleHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortDoubleHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortDoubleMap + *

+ * {@inheritDoc} + */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortDoubleHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TShortSet)) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TShortProcedure() { + private boolean first = true; + + + public boolean execute( short key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TDoubleCollection { + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TShortDoubleValueHashIterator( TShortDoubleHashMap.this ); + } + + + /** {@inheritDoc} */ + public double getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( double entry ) { + return TShortDoubleHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + return TShortDoubleHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + return TShortDoubleHashMap.this.values( dest ); + } + + + + public boolean add( double entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( double entry ) { + double[] values = _values; + short[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double ele = ( ( Double ) element ).doubleValue(); + if ( ! TShortDoubleHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortDoubleHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( double element : array ) { + if ( ! TShortDoubleHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortDoubleHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TDoubleProcedure procedure ) { + return TShortDoubleHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TDoubleProcedure() { + private boolean first = true; + + public boolean execute( double value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TShortDoubleKeyHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortDoubleKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TShortDoubleValueHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortDoubleValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TShortDoubleHashIterator extends THashPrimitiveIterator implements TShortDoubleIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TShortDoubleHashMap we will be iterating over. + */ + TShortDoubleHashIterator( TShortDoubleHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public double value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public double setValue( double val ) { + double old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortDoubleHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortDoubleMap ) ) { + return false; + } + TShortDoubleMap that = ( TShortDoubleMap ) other; + if ( that.size() != this.size() ) { + return false; + } + double[] values = _values; + byte[] states = _states; + double this_no_entry_value = getNoEntryValue(); + double that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + short key = _set[i]; + double that_value = that.get( key ); + double this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TShortDoubleProcedure() { + private boolean first = true; + public boolean execute( short key, double value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeDouble( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + double val = in.readDouble(); + put(key, val); + } + } +} // TShortDoubleHashMap diff --git a/src/gnu/trove/map/hash/TShortFloatHashMap.java b/src/gnu/trove/map/hash/TShortFloatHashMap.java new file mode 100644 index 0000000..f1e6f3b --- /dev/null +++ b/src/gnu/trove/map/hash/TShortFloatHashMap.java @@ -0,0 +1,1311 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TFloatCollection; +import gnu.trove.TShortCollection; +import gnu.trove.function.TFloatFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.impl.hash.TShortFloatHash; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.iterator.TShortFloatIterator; +import gnu.trove.iterator.TShortIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TShortFloatMap; +import gnu.trove.procedure.TFloatProcedure; +import gnu.trove.procedure.TShortFloatProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.set.TShortSet; + +/** + * An open addressed Map implementation for short keys and float values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TShortFloatHashMap extends TShortFloatHash implements TShortFloatMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient float[] _values; + + + /** + * Creates a new TShortFloatHashMap instance with the default + * capacity and load factor. + */ + public TShortFloatHashMap() { + super(); + } + + + /** + * Creates a new TShortFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortFloatHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TShortFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortFloatHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TShortFloatHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a short value that represents + * null for the Key set. + * @param noEntryValue a float value that represents + * null for the Value set. + */ + public TShortFloatHashMap( int initialCapacity, float loadFactor, + short noEntryKey, float noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TShortFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a short array containing the keys for the matching values. + * @param values a float array containing the values. + */ + public TShortFloatHashMap( short[] keys, float[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TShortFloatHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TShortFloatMap that will be duplicated. + */ + public TShortFloatHashMap( TShortFloatMap map ) { + super( map.size() ); + if ( map instanceof TShortFloatHashMap ) { + TShortFloatHashMap hashmap = ( TShortFloatHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new float[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + float oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public float put( short key, float value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public float putIfAbsent( short key, float value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private float doPut( short key, float value, int index ) { + float previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().shortValue(), entry.getValue().floatValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortFloatMap map ) { + ensureCapacity( map.size() ); + TShortFloatIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public float get( short key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public float remove( short key ) { + float prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public short[] keys() { + short[] keys = new short[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public short[] keys( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TFloatCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public float[] values() { + float[] vals = new float[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public float[] values( float[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new float[size]; + } + + float[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( float val ) { + byte[] states = _states; + float[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TShortFloatIterator iterator() { + return new TShortFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TFloatProcedure procedure ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TShortFloatProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + float[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TFloatFunction function ) { + byte[] states = _states; + float[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TShortFloatProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + float[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( short key ) { + return adjustValue( key, ( float ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( short key, float amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public float adjustOrPutValue( short key, float adjust_amount, float put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final float newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TShortSet { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortFloatKeyHashIterator( TShortFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortFloatHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortFloatHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortFloatHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortFloatMap + *

+ * {@inheritDoc} + */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return no_entry_value != TShortFloatHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortFloatHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortFloatHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortFloatHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortFloatMap + *

+ * {@inheritDoc} + */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortFloatHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TShortSet)) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TShortProcedure() { + private boolean first = true; + + + public boolean execute( short key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TFloatCollection { + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TShortFloatValueHashIterator( TShortFloatHashMap.this ); + } + + + /** {@inheritDoc} */ + public float getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( float entry ) { + return TShortFloatHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + return TShortFloatHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + return TShortFloatHashMap.this.values( dest ); + } + + + + public boolean add( float entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( float entry ) { + float[] values = _values; + short[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float ele = ( ( Float ) element ).floatValue(); + if ( ! TShortFloatHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortFloatHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( float element : array ) { + if ( ! TShortFloatHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortFloatHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TFloatProcedure procedure ) { + return TShortFloatHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TFloatProcedure() { + private boolean first = true; + + public boolean execute( float value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TShortFloatKeyHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortFloatKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TShortFloatValueHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortFloatValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TShortFloatHashIterator extends THashPrimitiveIterator implements TShortFloatIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TShortFloatHashMap we will be iterating over. + */ + TShortFloatHashIterator( TShortFloatHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public float value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public float setValue( float val ) { + float old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortFloatHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortFloatMap ) ) { + return false; + } + TShortFloatMap that = ( TShortFloatMap ) other; + if ( that.size() != this.size() ) { + return false; + } + float[] values = _values; + byte[] states = _states; + float this_no_entry_value = getNoEntryValue(); + float that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + short key = _set[i]; + float that_value = that.get( key ); + float this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TShortFloatProcedure() { + private boolean first = true; + public boolean execute( short key, float value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeFloat( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + float val = in.readFloat(); + put(key, val); + } + } +} // TShortFloatHashMap diff --git a/src/gnu/trove/map/hash/TShortIntHashMap.java b/src/gnu/trove/map/hash/TShortIntHashMap.java new file mode 100644 index 0000000..8537d26 --- /dev/null +++ b/src/gnu/trove/map/hash/TShortIntHashMap.java @@ -0,0 +1,1300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TShortIntMap; +import gnu.trove.function.TIntFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for short keys and int values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TShortIntHashMap extends TShortIntHash implements TShortIntMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient int[] _values; + + + /** + * Creates a new TShortIntHashMap instance with the default + * capacity and load factor. + */ + public TShortIntHashMap() { + super(); + } + + + /** + * Creates a new TShortIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortIntHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TShortIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortIntHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TShortIntHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a short value that represents + * null for the Key set. + * @param noEntryValue a int value that represents + * null for the Value set. + */ + public TShortIntHashMap( int initialCapacity, float loadFactor, + short noEntryKey, int noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TShortIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a short array containing the keys for the matching values. + * @param values a int array containing the values. + */ + public TShortIntHashMap( short[] keys, int[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TShortIntHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TShortIntMap that will be duplicated. + */ + public TShortIntHashMap( TShortIntMap map ) { + super( map.size() ); + if ( map instanceof TShortIntHashMap ) { + TShortIntHashMap hashmap = ( TShortIntHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new int[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + int oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public int put( short key, int value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public int putIfAbsent( short key, int value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private int doPut( short key, int value, int index ) { + int previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().shortValue(), entry.getValue().intValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortIntMap map ) { + ensureCapacity( map.size() ); + TShortIntIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public int get( short key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public int remove( short key ) { + int prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public short[] keys() { + short[] keys = new short[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public short[] keys( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TIntCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public int[] values() { + int[] vals = new int[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public int[] values( int[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new int[size]; + } + + int[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( int val ) { + byte[] states = _states; + int[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TShortIntIterator iterator() { + return new TShortIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TIntProcedure procedure ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TShortIntProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + int[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TIntFunction function ) { + byte[] states = _states; + int[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TShortIntProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + int[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( short key ) { + return adjustValue( key, ( int ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( short key, int amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public int adjustOrPutValue( short key, int adjust_amount, int put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final int newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TShortSet { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortIntKeyHashIterator( TShortIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortIntHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortIntHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortIntHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortIntMap + *

+ * {@inheritDoc} + */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return no_entry_value != TShortIntHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortIntHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortIntHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortIntHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortIntMap + *

+ * {@inheritDoc} + */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortIntHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TShortSet)) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TShortProcedure() { + private boolean first = true; + + + public boolean execute( short key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TIntCollection { + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TShortIntValueHashIterator( TShortIntHashMap.this ); + } + + + /** {@inheritDoc} */ + public int getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( int entry ) { + return TShortIntHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + return TShortIntHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + return TShortIntHashMap.this.values( dest ); + } + + + + public boolean add( int entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( int entry ) { + int[] values = _values; + short[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int ele = ( ( Integer ) element ).intValue(); + if ( ! TShortIntHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortIntHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int element : array ) { + if ( ! TShortIntHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortIntHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TIntProcedure procedure ) { + return TShortIntHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TIntProcedure() { + private boolean first = true; + + public boolean execute( int value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TShortIntKeyHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortIntKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TShortIntValueHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortIntValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TShortIntHashIterator extends THashPrimitiveIterator implements TShortIntIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TShortIntHashMap we will be iterating over. + */ + TShortIntHashIterator( TShortIntHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public int value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public int setValue( int val ) { + int old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortIntHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortIntMap ) ) { + return false; + } + TShortIntMap that = ( TShortIntMap ) other; + if ( that.size() != this.size() ) { + return false; + } + int[] values = _values; + byte[] states = _states; + int this_no_entry_value = getNoEntryValue(); + int that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + short key = _set[i]; + int that_value = that.get( key ); + int this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TShortIntProcedure() { + private boolean first = true; + public boolean execute( short key, int value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeInt( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + int val = in.readInt(); + put(key, val); + } + } +} // TShortIntHashMap diff --git a/src/gnu/trove/map/hash/TShortLongHashMap.java b/src/gnu/trove/map/hash/TShortLongHashMap.java new file mode 100644 index 0000000..0e89ed3 --- /dev/null +++ b/src/gnu/trove/map/hash/TShortLongHashMap.java @@ -0,0 +1,1300 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TShortLongMap; +import gnu.trove.function.TLongFunction; +import gnu.trove.procedure.*; +import gnu.trove.set.*; +import gnu.trove.iterator.*; +import gnu.trove.iterator.hash.*; +import gnu.trove.impl.hash.*; +import gnu.trove.impl.HashFunctions; +import gnu.trove.*; + +import java.io.*; +import java.util.*; + +/** + * An open addressed Map implementation for short keys and long values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +@SuppressWarnings("unused") +public class TShortLongHashMap extends TShortLongHash implements TShortLongMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient long[] _values; + + + /** + * Creates a new TShortLongHashMap instance with the default + * capacity and load factor. + */ + public TShortLongHashMap() { + super(); + } + + + /** + * Creates a new TShortLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortLongHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TShortLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortLongHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TShortLongHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a short value that represents + * null for the Key set. + * @param noEntryValue a long value that represents + * null for the Value set. + */ + public TShortLongHashMap( int initialCapacity, float loadFactor, + short noEntryKey, long noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TShortLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a short array containing the keys for the matching values. + * @param values a long array containing the values. + */ + public TShortLongHashMap( short[] keys, long[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TShortLongHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TShortLongMap that will be duplicated. + */ + public TShortLongHashMap( TShortLongMap map ) { + super( map.size() ); + if ( map instanceof TShortLongHashMap ) { + TShortLongHashMap hashmap = ( TShortLongHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new long[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + long oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public long put( short key, long value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public long putIfAbsent( short key, long value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private long doPut( short key, long value, int index ) { + long previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().shortValue(), entry.getValue().longValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortLongMap map ) { + ensureCapacity( map.size() ); + TShortLongIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public long get( short key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public long remove( short key ) { + long prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public short[] keys() { + short[] keys = new short[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public short[] keys( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TLongCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public long[] values() { + long[] vals = new long[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public long[] values( long[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new long[size]; + } + + long[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( long val ) { + byte[] states = _states; + long[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TShortLongIterator iterator() { + return new TShortLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TLongProcedure procedure ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TShortLongProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + long[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TLongFunction function ) { + byte[] states = _states; + long[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TShortLongProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + long[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( short key ) { + return adjustValue( key, ( long ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( short key, long amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public long adjustOrPutValue( short key, long adjust_amount, long put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final long newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + byte previousState = _states[index]; + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TShortSet { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortLongKeyHashIterator( TShortLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortLongHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortLongHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortLongHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortLongMap + *

+ * {@inheritDoc} + */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return no_entry_value != TShortLongHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortLongHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortLongHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortLongHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortLongMap + *

+ * {@inheritDoc} + */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortLongHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TShortSet)) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TShortProcedure() { + private boolean first = true; + + + public boolean execute( short key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TLongCollection { + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TShortLongValueHashIterator( TShortLongHashMap.this ); + } + + + /** {@inheritDoc} */ + public long getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( long entry ) { + return TShortLongHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + return TShortLongHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + return TShortLongHashMap.this.values( dest ); + } + + + + public boolean add( long entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( long entry ) { + long[] values = _values; + short[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long ele = ( ( Long ) element ).longValue(); + if ( ! TShortLongHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortLongHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( long element : array ) { + if ( ! TShortLongHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortLongHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TLongProcedure procedure ) { + return TShortLongHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TLongProcedure() { + private boolean first = true; + + public boolean execute( long value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TShortLongKeyHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortLongKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TShortLongValueHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortLongValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TShortLongHashIterator extends THashPrimitiveIterator implements TShortLongIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TShortLongHashMap we will be iterating over. + */ + TShortLongHashIterator( TShortLongHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public long value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public long setValue( long val ) { + long old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortLongHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortLongMap ) ) { + return false; + } + TShortLongMap that = ( TShortLongMap ) other; + if ( that.size() != this.size() ) { + return false; + } + long[] values = _values; + byte[] states = _states; + long this_no_entry_value = getNoEntryValue(); + long that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + short key = _set[i]; + long that_value = that.get( key ); + long this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TShortLongProcedure() { + private boolean first = true; + public boolean execute( short key, long value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeLong( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + long val = in.readLong(); + put(key, val); + } + } +} // TShortLongHashMap diff --git a/src/gnu/trove/map/hash/TShortObjectHashMap.java b/src/gnu/trove/map/hash/TShortObjectHashMap.java new file mode 100644 index 0000000..cd7d528 --- /dev/null +++ b/src/gnu/trove/map/hash/TShortObjectHashMap.java @@ -0,0 +1,1030 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + +import gnu.trove.map.TShortObjectMap; +import gnu.trove.impl.Constants; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.*; +import gnu.trove.procedure.TShortObjectProcedure; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.iterator.TShortIterator; +import gnu.trove.iterator.TShortObjectIterator; +import gnu.trove.iterator.TPrimitiveIterator; +import gnu.trove.function.TObjectFunction; +import gnu.trove.set.TShortSet; +import gnu.trove.TShortCollection; + +import java.io.*; +import java.util.*; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed Map implementation for short keys and Object values. + * + * Created: Sun Nov 4 08:52:45 2001 + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ +@SuppressWarnings("unused") +public class TShortObjectHashMap extends TShortHash implements + TShortObjectMap, Externalizable { + + static final long serialVersionUID = 1L; + + private final TShortObjectProcedure PUT_ALL_PROC = new TShortObjectProcedure() { + public boolean execute( short key, V value) { + put( key, value ); + return true; + } + }; + + /** the values of the map */ + protected transient V[] _values; + + /** the value that represents null in the key set. */ + protected short no_entry_key; + + + /** + * Creates a new TShortObjectHashMap instance with the default + * capacity and load factor. + */ + public TShortObjectHashMap() { + super(); + } + + + /** + * Creates a new TShortObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortObjectHashMap( int initialCapacity ) { + super( initialCapacity ); + no_entry_key = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TShortObjectHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortObjectHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + no_entry_key = Constants.DEFAULT_SHORT_NO_ENTRY_VALUE; + } + + + /** + * Creates a new TShortObjectHashMap instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param loadFactor used to calculate the threshold over which + * rehashing takes place. + * @param noEntryKey the value used to represent null in the key set. + */ + public TShortObjectHashMap( int initialCapacity, float loadFactor, short noEntryKey ) { + super( initialCapacity, loadFactor ); + no_entry_key = noEntryKey; + } + + + /** + * Creates a new TShortObjectHashMap that contains the entries + * in the map passed to it. + * + * @param map the TShortObjectMap to be copied. + */ + public TShortObjectHashMap( TShortObjectMap map ) { + this( map.size(), 0.5f, map.getNoEntryKey() ); + putAll( map ); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = ( V[] ) new Object[capacity]; + return capacity; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + V oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = (V[]) new Object[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey(o); + _values[index] = oldVals[i]; + } + } + } + + + // Query Operations + + /** {@inheritDoc} */ + public short getNoEntryKey() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public boolean containsValue( Object val ) { + byte[] states = _states; + V[] vals = _values; + + // special case null values so that we don't have to + // perform null checks before every call to equals() + if ( null == val ) { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && null == vals[i] ) { + return true; + } + } + } else { + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && + ( val == vals[i] || val.equals( vals[i] ) ) ) { + return true; + } + } + } // end of else + return false; + } + + + /** {@inheritDoc} */ + public V get( short key ) { + int index = index( key ); + return index < 0 ? null : _values[index]; + } + + + // Modification Operations + + /** {@inheritDoc} */ + public V put( short key, V value ) { + int index = insertKey( key ); + return doPut( value, index ); + } + + + /** {@inheritDoc} */ + public V putIfAbsent( short key, V value ) { + int index = insertKey( key ); + if ( index < 0 ) + return _values[-index - 1]; + return doPut( value, index ); + } + + + @SuppressWarnings({}) + private V doPut( V value, int index ) { + V previous = null; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public V remove( short key ) { + V prev = null; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = null; + super.removeAt( index ); // clear key, state; adjust size + } + + + // Bulk Operations + + /** {@inheritDoc} */ + public void putAll( Map map ) { + Set> set = map.entrySet(); + for ( Map.Entry entry : set ) { + put( entry.getKey(), entry.getValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortObjectMap map ){ + map.forEachEntry( PUT_ALL_PROC ); + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _states, 0, _states.length, FREE ); + Arrays.fill( _values, 0, _values.length, null ); + } + + + // Views + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new KeyView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public short[] keys() { + short[] keys = new short[size()]; + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public short[] keys( short[] dest ) { + if ( dest.length < _size ) { + dest = new short[_size]; + } + + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = k[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public Collection valueCollection() { + return new ValueView(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public Object[] values() { + Object[] vals = new Object[size()]; + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({"unchecked"}) + public V[] values( V[] dest ) { + if ( dest.length < _size ) { + dest = ( V[] ) java.lang.reflect.Array.newInstance( + dest.getClass().getComponentType(), _size); + } + + V[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = ( V ) v[i]; + } + } + return dest; + } + + + /** {@inheritDoc} */ + public TShortObjectIterator iterator() { + return new TShortObjectHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TObjectProcedure procedure ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean forEachEntry( TShortObjectProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + V[] values = _values; + for (int i = keys.length; i-- > 0;) { + if (states[i] == FULL && ! procedure.execute(keys[i],values[i])) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainEntries( TShortObjectProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + V[] values = _values; + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public void transformValues( TObjectFunction function ) { + byte[] states = _states; + V[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + // Comparison and hashing + + /** {@inheritDoc} */ + @SuppressWarnings("rawtypes") + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortObjectMap ) ) { + return false; + } + TShortObjectMap that = ( TShortObjectMap ) other; + if ( that.size() != this.size() ) { + return false; + } + try { + TShortObjectIterator iter = this.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + short key = iter.key(); + Object value = iter.value(); + if ( value == null ) { + if ( !( that.get( key ) == null && that.containsKey( key ) ) ) { + return false; + } + } else { + if ( !value.equals( that.get( key ) ) ) { + return false; + } + } + } + } catch ( ClassCastException ex ) { + // unused. + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + V[] values = _values; + byte[] states = _states; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + ( values[i] == null ? 0 : values[i].hashCode() ); + } + } + return hashcode; + } + + + class KeyView implements TShortSet { + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + /** {@inheritDoc} */ + public boolean isEmpty() { + return _size == 0; + } + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortObjectHashMap.this.containsKey( entry ); + } + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortHashIterator( TShortObjectHashMap.this ); + } + + /** {@inheritDoc} */ + public short[] toArray() { + return keys(); + } + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return keys( dest ); + } + + /** {@inheritDoc} */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return null != TShortObjectHashMap.this.remove( entry ); + } + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( ! TShortObjectHashMap.this.containsKey( + ( ( Short ) element ).shortValue() ) ) { + + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + if ( collection == this ) { + return true; + } + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortObjectHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortObjectHashMap.this.containsKey( element ) ) { + return false; + } + } + return true; + } + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + /** {@inheritDoc} */ + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + //noinspection SuspiciousMethodCalls + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( collection == this ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + /** {@inheritDoc} */ + public void clear() { + TShortObjectHashMap.this.clear(); + } + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortObjectHashMap.this.forEachKey( procedure ); + } + + /** {@inheritDoc) */ + public boolean equals( Object other ) { + if (! ( other instanceof TShortSet ) ) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + /** {@inheritDoc} */ + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( first ) first = false; + else buf.append( "," ); + buf.append( _set[i] ); + } + } + return buf.toString(); + } + + + class TShortHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** the collection on which the iterator operates */ + private final TShortHash _hash; + + /** {@inheritDoc} */ + public TShortHashIterator( TShortHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + } + + + /** a view onto the values of the map. */ + protected class ValueView extends MapBackedView { + + @SuppressWarnings({}) + public Iterator iterator() { + return new TShortObjectValueHashIterator( TShortObjectHashMap.this ) { + protected V objectAtIndex( int index ) { + return _values[index]; + } + }; + } + + public boolean containsElement( V value ) { + return containsValue( value ); + } + + public boolean removeElement( V value ) { + V[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + if ( value == values[i] || + ( null != values[i] && values[i].equals( value ) ) ) { + removeAt( i ); + return true; + } + } + } + return false; + } + + class TShortObjectValueHashIterator extends THashPrimitiveIterator + implements Iterator { + + @SuppressWarnings("rawtypes") + protected final TShortObjectHashMap _map; + + @SuppressWarnings("rawtypes") + public TShortObjectValueHashIterator( TShortObjectHashMap map ) { + super( map ); + _map = map; + } + + @SuppressWarnings("unchecked") + protected V objectAtIndex( int index ) { + byte[] states = _states; + Object value = _map._values[index]; + if ( states[index] != FULL ) { + return null; + } + return ( V ) value; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + public V next() { + moveToNextIndex(); + return ( V ) _map._values[_index]; + } + } + } + + + private abstract class MapBackedView extends AbstractSet + implements Set, Iterable { + + public abstract Iterator iterator(); + + public abstract boolean removeElement( E key ); + + public abstract boolean containsElement( E key ); + + @SuppressWarnings({"unchecked"}) + public boolean contains( Object key ) { + return containsElement( (E) key ); + } + + @SuppressWarnings({"unchecked"}) + public boolean remove( Object o ) { + return removeElement( (E) o ); + } + + public void clear() { + TShortObjectHashMap.this.clear(); + } + + public boolean add( E obj ) { + throw new UnsupportedOperationException(); + } + + public int size() { + return TShortObjectHashMap.this.size(); + } + + public Object[] toArray() { + Object[] result = new Object[size()]; + Iterator e = iterator(); + for ( int i = 0; e.hasNext(); i++ ) { + result[i] = e.next(); + } + return result; + } + + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) java.lang.reflect.Array.newInstance( + a.getClass().getComponentType(), size ); + } + + Iterator it = iterator(); + Object[] result = a; + for ( int i = 0; i < size; i++ ) { + result[i] = it.next(); + } + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + public boolean isEmpty() { + return TShortObjectHashMap.this.isEmpty(); + } + + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + Iterator i = iterator(); + while ( i.hasNext() ) { + if ( !collection.contains( i.next() ) ) { + i.remove(); + changed = true; + } + } + return changed; + } + } + + + @SuppressWarnings("hiding") + class TShortObjectHashIterator extends THashPrimitiveIterator + implements TShortObjectIterator { + + /** the collection being iterated over */ + private final TShortObjectHashMap _map; + + /** + * Creates an iterator over the specified map + * + * @param map map to iterate over. + */ + public TShortObjectHashIterator( TShortObjectHashMap map ) { + super( map ); + this._map = map; + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _map._set[_index]; + } + + /** {@inheritDoc} */ + public V value() { + return _map._values[_index]; + } + + /** {@inheritDoc} */ + public V setValue( V val ) { + V old = value(); + _map._values[_index] = val; + return old; + } + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NO_ENTRY_KEY + out.writeShort( no_entry_key ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeObject( _values[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NO_ENTRY_KEY + no_entry_key = in.readShort(); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + V val = (V) in.readObject(); + put(key, val); + } + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEachEntry(new TShortObjectProcedure() { + private boolean first = true; + public boolean execute(short key, Object value) { + if ( first ) first = false; + else buf.append( "," ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } +} // TShortObjectHashMap diff --git a/src/gnu/trove/map/hash/TShortShortHashMap.java b/src/gnu/trove/map/hash/TShortShortHashMap.java new file mode 100644 index 0000000..edb1ccf --- /dev/null +++ b/src/gnu/trove/map/hash/TShortShortHashMap.java @@ -0,0 +1,1308 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.map.hash; + + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Map; + +import gnu.trove.TShortCollection; +import gnu.trove.function.TShortFunction; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.THashPrimitiveIterator; +import gnu.trove.impl.hash.TPrimitiveHash; +import gnu.trove.impl.hash.TShortShortHash; +import gnu.trove.iterator.TShortIterator; +import gnu.trove.iterator.TShortShortIterator; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.map.TShortShortMap; +import gnu.trove.procedure.TShortProcedure; +import gnu.trove.procedure.TShortShortProcedure; +import gnu.trove.set.TShortSet; + +/** + * An open addressed Map implementation for short keys and short values. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: _K__V_HashMap.template,v 1.1.2.16 2010/03/02 04:09:50 robeden Exp $ + */ +public class TShortShortHashMap extends TShortShortHash implements TShortShortMap, Externalizable { + static final long serialVersionUID = 1L; + + /** the values of the map */ + protected transient short[] _values; + + + /** + * Creates a new TShortShortHashMap instance with the default + * capacity and load factor. + */ + public TShortShortHashMap() { + super(); + } + + + /** + * Creates a new TShortShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortShortHashMap( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TShortShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TShortShortHashMap( int initialCapacity, float loadFactor ) { + super( initialCapacity, loadFactor ); + } + + + /** + * Creates a new TShortShortHashMap instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + * @param noEntryKey a short value that represents + * null for the Key set. + * @param noEntryValue a short value that represents + * null for the Value set. + */ + public TShortShortHashMap( int initialCapacity, float loadFactor, + short noEntryKey, short noEntryValue ) { + super( initialCapacity, loadFactor, noEntryKey, noEntryValue ); + } + + + /** + * Creates a new TShortShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param keys a short array containing the keys for the matching values. + * @param values a short array containing the values. + */ + public TShortShortHashMap( short[] keys, short[] values ) { + super( Math.max( keys.length, values.length ) ); + + int size = Math.min( keys.length, values.length ); + for ( int i = 0; i < size; i++ ) { + this.put( keys[i], values[i] ); + } + } + + + /** + * Creates a new TShortShortHashMap instance containing + * all of the entries in the map passed in. + * + * @param map a TShortShortMap that will be duplicated. + */ + public TShortShortHashMap( TShortShortMap map ) { + super( map.size() ); + if ( map instanceof TShortShortHashMap ) { + TShortShortHashMap hashmap = ( TShortShortHashMap ) map; + this._loadFactor = hashmap._loadFactor; + this.no_entry_key = hashmap.no_entry_key; + this.no_entry_value = hashmap.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_key != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_key ); + } + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _values, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + putAll( map ); + } + + + /** + * initializes the hashtable to a prime capacity which is at least + * initialCapacity + 1. + * + * @param initialCapacity an int value + * @return the actual capacity chosen + */ + protected int setUp( int initialCapacity ) { + int capacity; + + capacity = super.setUp( initialCapacity ); + _values = new short[capacity]; + return capacity; + } + + + /** + * rehashes the map to the new capacity. + * + * @param newCapacity an int value + */ + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldKeys[] = _set; + short oldVals[] = _values; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _values = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldKeys[i]; + int index = insertKey( o ); + _values[index] = oldVals[i]; + } + } + } + + + /** {@inheritDoc} */ + public short put( short key, short value ) { + int index = insertKey( key ); + return doPut( key, value, index ); + } + + + /** {@inheritDoc} */ + public short putIfAbsent( short key, short value ) { + int index = insertKey( key ); + if (index < 0) + return _values[-index - 1]; + return doPut( key, value, index ); + } + + + private short doPut( short key, short value, int index ) { + short previous = no_entry_value; + boolean isNewMapping = true; + if ( index < 0 ) { + index = -index -1; + previous = _values[index]; + isNewMapping = false; + } + _values[index] = value; + + if (isNewMapping) { + postInsertHook( consumeFreeSlot ); + } + + return previous; + } + + + /** {@inheritDoc} */ + public void putAll( Map map ) { + ensureCapacity( map.size() ); + // could optimize this for cases when map instanceof THashMap + for ( Map.Entry entry : map.entrySet() ) { + this.put( entry.getKey().shortValue(), entry.getValue().shortValue() ); + } + } + + + /** {@inheritDoc} */ + public void putAll( TShortShortMap map ) { + ensureCapacity( map.size() ); + TShortShortIterator iter = map.iterator(); + while ( iter.hasNext() ) { + iter.advance(); + this.put( iter.key(), iter.value() ); + } + } + + + /** {@inheritDoc} */ + public short get( short key ) { + int index = index( key ); + return index < 0 ? no_entry_value : _values[index]; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + Arrays.fill( _set, 0, _set.length, no_entry_key ); + Arrays.fill( _values, 0, _values.length, no_entry_value ); + Arrays.fill( _states, 0, _states.length, FREE ); + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public short remove( short key ) { + short prev = no_entry_value; + int index = index( key ); + if ( index >= 0 ) { + prev = _values[index]; + removeAt( index ); // clear key,state; adjust size + } + return prev; + } + + + /** {@inheritDoc} */ + protected void removeAt( int index ) { + _values[index] = no_entry_value; + super.removeAt( index ); // clear key, state; adjust size + } + + + /** {@inheritDoc} */ + public TShortSet keySet() { + return new TKeyView(); + } + + + /** {@inheritDoc} */ + public short[] keys() { + short[] keys = new short[size()]; + if ( keys.length == 0 ) { + return keys; // nothing to copy + } + short[] k = _set; + byte[] states = _states; + + for ( int i = k.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + keys[j++] = k[i]; + } + } + return keys; + } + + + /** {@inheritDoc} */ + public short[] keys( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] keys = _set; + byte[] states = _states; + + for ( int i = keys.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = keys[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public TShortCollection valueCollection() { + return new TValueView(); + } + + + /** {@inheritDoc} */ + public short[] values() { + short[] vals = new short[size()]; + if ( vals.length == 0 ) { + return vals; // nothing to copy + } + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + vals[j++] = v[i]; + } + } + return vals; + } + + + /** {@inheritDoc} */ + public short[] values( short[] array ) { + int size = size(); + if ( size == 0 ) { + return array; // nothing to copy + } + if ( array.length < size ) { + array = new short[size]; + } + + short[] v = _values; + byte[] states = _states; + + for ( int i = v.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + array[j++] = v[i]; + } + } + return array; + } + + + /** {@inheritDoc} */ + public boolean containsValue( short val ) { + byte[] states = _states; + short[] vals = _values; + + for ( int i = vals.length; i-- > 0; ) { + if ( states[i] == FULL && val == vals[i] ) { + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsKey( short key ) { + return contains( key ); + } + + + /** {@inheritDoc} */ + public TShortShortIterator iterator() { + return new TShortShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public boolean forEachKey( TShortProcedure procedure ) { + return forEach( procedure ); + } + + + /** {@inheritDoc} */ + public boolean forEachValue( TShortProcedure procedure ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean forEachEntry( TShortShortProcedure procedure ) { + byte[] states = _states; + short[] keys = _set; + short[] values = _values; + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public void transformValues( TShortFunction function ) { + byte[] states = _states; + short[] values = _values; + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + values[i] = function.execute( values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public boolean retainEntries( TShortShortProcedure procedure ) { + boolean modified = false; + byte[] states = _states; + short[] keys = _set; + short[] values = _values; + + + // Temporarily disable compaction. This is a fix for bug #1738760 + tempDisableAutoCompaction(); + try { + for ( int i = keys.length; i-- > 0; ) { + if ( states[i] == FULL && ! procedure.execute( keys[i], values[i] ) ) { + removeAt( i ); + modified = true; + } + } + } + finally { + reenableAutoCompaction( true ); + } + + return modified; + } + + + /** {@inheritDoc} */ + public boolean increment( short key ) { + return adjustValue( key, ( short ) 1 ); + } + + + /** {@inheritDoc} */ + public boolean adjustValue( short key, short amount ) { + int index = index( key ); + if (index < 0) { + return false; + } else { + _values[index] += amount; + return true; + } + } + + + /** {@inheritDoc} */ + public short adjustOrPutValue( short key, short adjust_amount, short put_amount ) { + int index = insertKey( key ); + final boolean isNewMapping; + final short newValue; + if ( index < 0 ) { + index = -index -1; + newValue = ( _values[index] += adjust_amount ); + isNewMapping = false; + } else { + newValue = ( _values[index] = put_amount ); + isNewMapping = true; + } + + + if ( isNewMapping ) { + postInsertHook(consumeFreeSlot); + } + + return newValue; + } + + + /** a view onto the keys of the map. */ + protected class TKeyView implements TShortSet { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortShortKeyHashIterator( TShortShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_key; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortShortHashMap.this.contains( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortShortHashMap.this.keys(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortShortHashMap.this.keys( dest ); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortShortMap + *

+ * {@inheritDoc} + */ + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + return no_entry_value != TShortShortHashMap.this.remove( entry ); + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortShortHashMap.this.containsKey( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortShortHashMap.this.containsKey( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortShortHashMap.this.contains( element ) ) { + return false; + } + } + return true; + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** + * Unsupported when operating upon a Key Set view of a TShortShortMap + *

+ * {@inheritDoc} + */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortShortHashMap.this.forEachKey( procedure ); + } + + + @Override + public boolean equals( Object other ) { + if (! (other instanceof TShortSet)) { + return false; + } + final TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + @Override + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachKey( new TShortProcedure() { + private boolean first = true; + + + public boolean execute( short key ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( key ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + /** a view onto the values of the map. */ + protected class TValueView implements TShortCollection { + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortShortValueHashIterator( TShortShortHashMap.this ); + } + + + /** {@inheritDoc} */ + public short getNoEntryValue() { + return no_entry_value; + } + + + /** {@inheritDoc} */ + public int size() { + return _size; + } + + + /** {@inheritDoc} */ + public boolean isEmpty() { + return 0 == _size; + } + + + /** {@inheritDoc} */ + public boolean contains( short entry ) { + return TShortShortHashMap.this.containsValue( entry ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + return TShortShortHashMap.this.values(); + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + return TShortShortHashMap.this.values( dest ); + } + + + + public boolean add( short entry ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean remove( short entry ) { + short[] values = _values; + short[] set = _set; + + for ( int i = values.length; i-- > 0; ) { + if ( ( set[i] != FREE && set[i] != REMOVED ) && entry == values[i] ) { + removeAt( i ); + return true; + } + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short ele = ( ( Short ) element ).shortValue(); + if ( ! TShortShortHashMap.this.containsValue( ele ) ) { + return false; + } + } else { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + if ( ! TShortShortHashMap.this.containsValue( iter.next() ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( short element : array ) { + if ( ! TShortShortHashMap.this.containsValue( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + throw new UnsupportedOperationException(); + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] values = _values; + byte[] states = _states; + + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, values[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + if ( this == collection ) { + clear(); + return true; + } + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + TShortShortHashMap.this.clear(); + } + + + /** {@inheritDoc} */ + public boolean forEach( TShortProcedure procedure ) { + return TShortShortHashMap.this.forEachValue( procedure ); + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachValue( new TShortProcedure() { + private boolean first = true; + + public boolean execute( short value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + } + + + class TShortShortKeyHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortShortKeyHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _set[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + + class TShortShortValueHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param hash the TPrimitiveHash we will be iterating over. + */ + TShortShortValueHashIterator( TPrimitiveHash hash ) { + super( hash ); + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _values[_index]; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + + _expectedSize--; + } + } + + + class TShortShortHashIterator extends THashPrimitiveIterator implements TShortShortIterator { + + /** + * Creates an iterator over the specified map + * + * @param map the TShortShortHashMap we will be iterating over. + */ + TShortShortHashIterator( TShortShortHashMap map ) { + super( map ); + } + + /** {@inheritDoc} */ + public void advance() { + moveToNextIndex(); + } + + /** {@inheritDoc} */ + public short key() { + return _set[_index]; + } + + /** {@inheritDoc} */ + public short value() { + return _values[_index]; + } + + /** {@inheritDoc} */ + public short setValue( short val ) { + short old = value(); + _values[_index] = val; + return old; + } + + /** @{inheritDoc} */ + public void remove() { + if ( _expectedSize != _hash.size() ) { + throw new ConcurrentModificationException(); + } + // Disable auto compaction during the remove. This is a workaround for bug 1642768. + try { + _hash.tempDisableAutoCompaction(); + TShortShortHashMap.this.removeAt( _index ); + } + finally { + _hash.reenableAutoCompaction( false ); + } + _expectedSize--; + } + } + + + /** {@inheritDoc} */ + @Override + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortShortMap ) ) { + return false; + } + TShortShortMap that = ( TShortShortMap ) other; + if ( that.size() != this.size() ) { + return false; + } + short[] values = _values; + byte[] states = _states; + short this_no_entry_value = getNoEntryValue(); + short that_no_entry_value = that.getNoEntryValue(); + for ( int i = values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + short key = _set[i]; + short that_value = that.get( key ); + short this_value = values[i]; + if ( ( this_value != that_value ) && + ( this_value != this_no_entry_value ) && + ( that_value != that_no_entry_value ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int hashcode = 0; + byte[] states = _states; + for ( int i = _values.length; i-- > 0; ) { + if ( states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ) ^ + HashFunctions.hash( _values[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEachEntry( new TShortShortProcedure() { + private boolean first = true; + public boolean execute( short key, short value ) { + if ( first ) first = false; + else buf.append( ", " ); + + buf.append(key); + buf.append("="); + buf.append(value); + return true; + } + }); + buf.append( "}" ); + return buf.toString(); + } + + + /** {@inheritDoc} */ + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte( 0 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + out.writeShort( _values[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + // VERSION + in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while (size-- > 0) { + short key = in.readShort(); + short val = in.readShort(); + put(key, val); + } + } +} // TShortShortHashMap diff --git a/src/gnu/trove/procedure/TByteByteProcedure.java b/src/gnu/trove/procedure/TByteByteProcedure.java new file mode 100644 index 0000000..565d892 --- /dev/null +++ b/src/gnu/trove/procedure/TByteByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and byte. + */ +public interface TByteByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, byte b ); +} diff --git a/src/gnu/trove/procedure/TByteCharProcedure.java b/src/gnu/trove/procedure/TByteCharProcedure.java new file mode 100644 index 0000000..33eb0fd --- /dev/null +++ b/src/gnu/trove/procedure/TByteCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and char. + */ +public interface TByteCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, char b ); +} diff --git a/src/gnu/trove/procedure/TByteDoubleProcedure.java b/src/gnu/trove/procedure/TByteDoubleProcedure.java new file mode 100644 index 0000000..4672d8d --- /dev/null +++ b/src/gnu/trove/procedure/TByteDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and double. + */ +public interface TByteDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, double b ); +} diff --git a/src/gnu/trove/procedure/TByteFloatProcedure.java b/src/gnu/trove/procedure/TByteFloatProcedure.java new file mode 100644 index 0000000..f8d55ef --- /dev/null +++ b/src/gnu/trove/procedure/TByteFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and float. + */ +public interface TByteFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, float b ); +} diff --git a/src/gnu/trove/procedure/TByteIntProcedure.java b/src/gnu/trove/procedure/TByteIntProcedure.java new file mode 100644 index 0000000..eed4259 --- /dev/null +++ b/src/gnu/trove/procedure/TByteIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and int. + */ +public interface TByteIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, int b ); +} diff --git a/src/gnu/trove/procedure/TByteLongProcedure.java b/src/gnu/trove/procedure/TByteLongProcedure.java new file mode 100644 index 0000000..2d5cbd6 --- /dev/null +++ b/src/gnu/trove/procedure/TByteLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and long. + */ +public interface TByteLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, long b ); +} diff --git a/src/gnu/trove/procedure/TByteObjectProcedure.java b/src/gnu/trove/procedure/TByteObjectProcedure.java new file mode 100644 index 0000000..0d58bc2 --- /dev/null +++ b/src/gnu/trove/procedure/TByteObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and Object. + */ +public interface TByteObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, T b ); +} diff --git a/src/gnu/trove/procedure/TByteProcedure.java b/src/gnu/trove/procedure/TByteProcedure.java new file mode 100644 index 0000000..6684ea1 --- /dev/null +++ b/src/gnu/trove/procedure/TByteProcedure.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures with one byte parameter. + */ +public interface TByteProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type byte + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte value ); +} diff --git a/src/gnu/trove/procedure/TByteShortProcedure.java b/src/gnu/trove/procedure/TByteShortProcedure.java new file mode 100644 index 0000000..d534148 --- /dev/null +++ b/src/gnu/trove/procedure/TByteShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type byte and short. + */ +public interface TByteShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a byte value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( byte a, short b ); +} diff --git a/src/gnu/trove/procedure/TCharByteProcedure.java b/src/gnu/trove/procedure/TCharByteProcedure.java new file mode 100644 index 0000000..35f990c --- /dev/null +++ b/src/gnu/trove/procedure/TCharByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and byte. + */ +public interface TCharByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, byte b ); +} diff --git a/src/gnu/trove/procedure/TCharCharProcedure.java b/src/gnu/trove/procedure/TCharCharProcedure.java new file mode 100644 index 0000000..3d8b08a --- /dev/null +++ b/src/gnu/trove/procedure/TCharCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and char. + */ +public interface TCharCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, char b ); +} diff --git a/src/gnu/trove/procedure/TCharDoubleProcedure.java b/src/gnu/trove/procedure/TCharDoubleProcedure.java new file mode 100644 index 0000000..0a4c355 --- /dev/null +++ b/src/gnu/trove/procedure/TCharDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and double. + */ +public interface TCharDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, double b ); +} diff --git a/src/gnu/trove/procedure/TCharFloatProcedure.java b/src/gnu/trove/procedure/TCharFloatProcedure.java new file mode 100644 index 0000000..9390f0c --- /dev/null +++ b/src/gnu/trove/procedure/TCharFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and float. + */ +public interface TCharFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, float b ); +} diff --git a/src/gnu/trove/procedure/TCharIntProcedure.java b/src/gnu/trove/procedure/TCharIntProcedure.java new file mode 100644 index 0000000..25ae5be --- /dev/null +++ b/src/gnu/trove/procedure/TCharIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and int. + */ +public interface TCharIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, int b ); +} diff --git a/src/gnu/trove/procedure/TCharLongProcedure.java b/src/gnu/trove/procedure/TCharLongProcedure.java new file mode 100644 index 0000000..3ef83b8 --- /dev/null +++ b/src/gnu/trove/procedure/TCharLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and long. + */ +public interface TCharLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, long b ); +} diff --git a/src/gnu/trove/procedure/TCharObjectProcedure.java b/src/gnu/trove/procedure/TCharObjectProcedure.java new file mode 100644 index 0000000..5ce3606 --- /dev/null +++ b/src/gnu/trove/procedure/TCharObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and Object. + */ +public interface TCharObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, T b ); +} diff --git a/src/gnu/trove/procedure/TCharProcedure.java b/src/gnu/trove/procedure/TCharProcedure.java new file mode 100644 index 0000000..21f4fe4 --- /dev/null +++ b/src/gnu/trove/procedure/TCharProcedure.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures with one char parameter. + */ +public interface TCharProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type char + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char value ); +} diff --git a/src/gnu/trove/procedure/TCharShortProcedure.java b/src/gnu/trove/procedure/TCharShortProcedure.java new file mode 100644 index 0000000..b140e96 --- /dev/null +++ b/src/gnu/trove/procedure/TCharShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type char and short. + */ +public interface TCharShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a char value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( char a, short b ); +} diff --git a/src/gnu/trove/procedure/TDoubleByteProcedure.java b/src/gnu/trove/procedure/TDoubleByteProcedure.java new file mode 100644 index 0000000..4c3f14c --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and byte. + */ +public interface TDoubleByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, byte b ); +} diff --git a/src/gnu/trove/procedure/TDoubleCharProcedure.java b/src/gnu/trove/procedure/TDoubleCharProcedure.java new file mode 100644 index 0000000..844e9c4 --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and char. + */ +public interface TDoubleCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, char b ); +} diff --git a/src/gnu/trove/procedure/TDoubleDoubleProcedure.java b/src/gnu/trove/procedure/TDoubleDoubleProcedure.java new file mode 100644 index 0000000..db12bc3 --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and double. + */ +public interface TDoubleDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, double b ); +} diff --git a/src/gnu/trove/procedure/TDoubleFloatProcedure.java b/src/gnu/trove/procedure/TDoubleFloatProcedure.java new file mode 100644 index 0000000..1661fb1 --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and float. + */ +public interface TDoubleFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, float b ); +} diff --git a/src/gnu/trove/procedure/TDoubleIntProcedure.java b/src/gnu/trove/procedure/TDoubleIntProcedure.java new file mode 100644 index 0000000..39b6fb6 --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and int. + */ +public interface TDoubleIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, int b ); +} diff --git a/src/gnu/trove/procedure/TDoubleLongProcedure.java b/src/gnu/trove/procedure/TDoubleLongProcedure.java new file mode 100644 index 0000000..b5cdb54 --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and long. + */ +public interface TDoubleLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, long b ); +} diff --git a/src/gnu/trove/procedure/TDoubleObjectProcedure.java b/src/gnu/trove/procedure/TDoubleObjectProcedure.java new file mode 100644 index 0000000..b02a54c --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and Object. + */ +public interface TDoubleObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, T b ); +} diff --git a/src/gnu/trove/procedure/TDoubleProcedure.java b/src/gnu/trove/procedure/TDoubleProcedure.java new file mode 100644 index 0000000..28f0b5a --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleProcedure.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures with one double parameter. + */ +public interface TDoubleProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type double + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double value ); +} diff --git a/src/gnu/trove/procedure/TDoubleShortProcedure.java b/src/gnu/trove/procedure/TDoubleShortProcedure.java new file mode 100644 index 0000000..90cb98a --- /dev/null +++ b/src/gnu/trove/procedure/TDoubleShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type double and short. + */ +public interface TDoubleShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a double value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( double a, short b ); +} diff --git a/src/gnu/trove/procedure/TFloatByteProcedure.java b/src/gnu/trove/procedure/TFloatByteProcedure.java new file mode 100644 index 0000000..c078b83 --- /dev/null +++ b/src/gnu/trove/procedure/TFloatByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and byte. + */ +public interface TFloatByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, byte b ); +} diff --git a/src/gnu/trove/procedure/TFloatCharProcedure.java b/src/gnu/trove/procedure/TFloatCharProcedure.java new file mode 100644 index 0000000..9869247 --- /dev/null +++ b/src/gnu/trove/procedure/TFloatCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and char. + */ +public interface TFloatCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, char b ); +} diff --git a/src/gnu/trove/procedure/TFloatDoubleProcedure.java b/src/gnu/trove/procedure/TFloatDoubleProcedure.java new file mode 100644 index 0000000..71bfda6 --- /dev/null +++ b/src/gnu/trove/procedure/TFloatDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and double. + */ +public interface TFloatDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, double b ); +} diff --git a/src/gnu/trove/procedure/TFloatFloatProcedure.java b/src/gnu/trove/procedure/TFloatFloatProcedure.java new file mode 100644 index 0000000..740904d --- /dev/null +++ b/src/gnu/trove/procedure/TFloatFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and float. + */ +public interface TFloatFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, float b ); +} diff --git a/src/gnu/trove/procedure/TFloatIntProcedure.java b/src/gnu/trove/procedure/TFloatIntProcedure.java new file mode 100644 index 0000000..f939e60 --- /dev/null +++ b/src/gnu/trove/procedure/TFloatIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and int. + */ +public interface TFloatIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, int b ); +} diff --git a/src/gnu/trove/procedure/TFloatLongProcedure.java b/src/gnu/trove/procedure/TFloatLongProcedure.java new file mode 100644 index 0000000..beab40b --- /dev/null +++ b/src/gnu/trove/procedure/TFloatLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and long. + */ +public interface TFloatLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, long b ); +} diff --git a/src/gnu/trove/procedure/TFloatObjectProcedure.java b/src/gnu/trove/procedure/TFloatObjectProcedure.java new file mode 100644 index 0000000..379fd47 --- /dev/null +++ b/src/gnu/trove/procedure/TFloatObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and Object. + */ +public interface TFloatObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, T b ); +} diff --git a/src/gnu/trove/procedure/TFloatProcedure.java b/src/gnu/trove/procedure/TFloatProcedure.java new file mode 100644 index 0000000..8bcdd82 --- /dev/null +++ b/src/gnu/trove/procedure/TFloatProcedure.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures with one float parameter. + */ +public interface TFloatProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type float + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float value ); +} diff --git a/src/gnu/trove/procedure/TFloatShortProcedure.java b/src/gnu/trove/procedure/TFloatShortProcedure.java new file mode 100644 index 0000000..831faa5 --- /dev/null +++ b/src/gnu/trove/procedure/TFloatShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type float and short. + */ +public interface TFloatShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a float value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( float a, short b ); +} diff --git a/src/gnu/trove/procedure/TIntByteProcedure.java b/src/gnu/trove/procedure/TIntByteProcedure.java new file mode 100644 index 0000000..fef5eec --- /dev/null +++ b/src/gnu/trove/procedure/TIntByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and byte. + */ +public interface TIntByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, byte b ); +} diff --git a/src/gnu/trove/procedure/TIntCharProcedure.java b/src/gnu/trove/procedure/TIntCharProcedure.java new file mode 100644 index 0000000..8c692f6 --- /dev/null +++ b/src/gnu/trove/procedure/TIntCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and char. + */ +public interface TIntCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, char b ); +} diff --git a/src/gnu/trove/procedure/TIntDoubleProcedure.java b/src/gnu/trove/procedure/TIntDoubleProcedure.java new file mode 100644 index 0000000..d1d8cd3 --- /dev/null +++ b/src/gnu/trove/procedure/TIntDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and double. + */ +public interface TIntDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, double b ); +} diff --git a/src/gnu/trove/procedure/TIntFloatProcedure.java b/src/gnu/trove/procedure/TIntFloatProcedure.java new file mode 100644 index 0000000..cb3235c --- /dev/null +++ b/src/gnu/trove/procedure/TIntFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and float. + */ +public interface TIntFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, float b ); +} diff --git a/src/gnu/trove/procedure/TIntIntProcedure.java b/src/gnu/trove/procedure/TIntIntProcedure.java new file mode 100644 index 0000000..97f012b --- /dev/null +++ b/src/gnu/trove/procedure/TIntIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and int. + */ +public interface TIntIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, int b ); +} diff --git a/src/gnu/trove/procedure/TIntLongProcedure.java b/src/gnu/trove/procedure/TIntLongProcedure.java new file mode 100644 index 0000000..45b3bb0 --- /dev/null +++ b/src/gnu/trove/procedure/TIntLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and long. + */ +public interface TIntLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, long b ); +} diff --git a/src/gnu/trove/procedure/TIntObjectProcedure.java b/src/gnu/trove/procedure/TIntObjectProcedure.java new file mode 100644 index 0000000..d763041 --- /dev/null +++ b/src/gnu/trove/procedure/TIntObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and Object. + */ +public interface TIntObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, T b ); +} diff --git a/src/gnu/trove/procedure/TIntProcedure.java b/src/gnu/trove/procedure/TIntProcedure.java new file mode 100644 index 0000000..5b1a644 --- /dev/null +++ b/src/gnu/trove/procedure/TIntProcedure.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures with one int parameter. + */ +public interface TIntProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int value ); +} diff --git a/src/gnu/trove/procedure/TIntShortProcedure.java b/src/gnu/trove/procedure/TIntShortProcedure.java new file mode 100644 index 0000000..90fec48 --- /dev/null +++ b/src/gnu/trove/procedure/TIntShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type int and short. + */ +public interface TIntShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a int value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( int a, short b ); +} diff --git a/src/gnu/trove/procedure/TLongByteProcedure.java b/src/gnu/trove/procedure/TLongByteProcedure.java new file mode 100644 index 0000000..51d840c --- /dev/null +++ b/src/gnu/trove/procedure/TLongByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and byte. + */ +public interface TLongByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, byte b ); +} diff --git a/src/gnu/trove/procedure/TLongCharProcedure.java b/src/gnu/trove/procedure/TLongCharProcedure.java new file mode 100644 index 0000000..22ea26e --- /dev/null +++ b/src/gnu/trove/procedure/TLongCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and char. + */ +public interface TLongCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, char b ); +} diff --git a/src/gnu/trove/procedure/TLongDoubleProcedure.java b/src/gnu/trove/procedure/TLongDoubleProcedure.java new file mode 100644 index 0000000..c2ba2a7 --- /dev/null +++ b/src/gnu/trove/procedure/TLongDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and double. + */ +public interface TLongDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, double b ); +} diff --git a/src/gnu/trove/procedure/TLongFloatProcedure.java b/src/gnu/trove/procedure/TLongFloatProcedure.java new file mode 100644 index 0000000..02f980c --- /dev/null +++ b/src/gnu/trove/procedure/TLongFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and float. + */ +public interface TLongFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, float b ); +} diff --git a/src/gnu/trove/procedure/TLongIntProcedure.java b/src/gnu/trove/procedure/TLongIntProcedure.java new file mode 100644 index 0000000..b29ed47 --- /dev/null +++ b/src/gnu/trove/procedure/TLongIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and int. + */ +public interface TLongIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, int b ); +} diff --git a/src/gnu/trove/procedure/TLongLongProcedure.java b/src/gnu/trove/procedure/TLongLongProcedure.java new file mode 100644 index 0000000..ebbacc2 --- /dev/null +++ b/src/gnu/trove/procedure/TLongLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and long. + */ +public interface TLongLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, long b ); +} diff --git a/src/gnu/trove/procedure/TLongObjectProcedure.java b/src/gnu/trove/procedure/TLongObjectProcedure.java new file mode 100644 index 0000000..3bcf152 --- /dev/null +++ b/src/gnu/trove/procedure/TLongObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and Object. + */ +public interface TLongObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, T b ); +} diff --git a/src/gnu/trove/procedure/TLongProcedure.java b/src/gnu/trove/procedure/TLongProcedure.java new file mode 100644 index 0000000..6b169f0 --- /dev/null +++ b/src/gnu/trove/procedure/TLongProcedure.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures with one long parameter. + */ +public interface TLongProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type long + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long value ); +} diff --git a/src/gnu/trove/procedure/TLongShortProcedure.java b/src/gnu/trove/procedure/TLongShortProcedure.java new file mode 100644 index 0000000..995987c --- /dev/null +++ b/src/gnu/trove/procedure/TLongShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type long and short. + */ +public interface TLongShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a long value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( long a, short b ); +} diff --git a/src/gnu/trove/procedure/TObjectByteProcedure.java b/src/gnu/trove/procedure/TObjectByteProcedure.java new file mode 100644 index 0000000..c576f21 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type Object and byte. + */ +public interface TObjectByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, byte b ); +} diff --git a/src/gnu/trove/procedure/TObjectCharProcedure.java b/src/gnu/trove/procedure/TObjectCharProcedure.java new file mode 100644 index 0000000..34c0c8a --- /dev/null +++ b/src/gnu/trove/procedure/TObjectCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type Object and char. + */ +public interface TObjectCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, char b ); +} diff --git a/src/gnu/trove/procedure/TObjectDoubleProcedure.java b/src/gnu/trove/procedure/TObjectDoubleProcedure.java new file mode 100644 index 0000000..61a3e22 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type Object and double. + */ +public interface TObjectDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, double b ); +} diff --git a/src/gnu/trove/procedure/TObjectFloatProcedure.java b/src/gnu/trove/procedure/TObjectFloatProcedure.java new file mode 100644 index 0000000..78ca9d0 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type Object and float. + */ +public interface TObjectFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, float b ); +} diff --git a/src/gnu/trove/procedure/TObjectIntProcedure.java b/src/gnu/trove/procedure/TObjectIntProcedure.java new file mode 100644 index 0000000..2f32664 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type Object and int. + */ +public interface TObjectIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, int b ); +} diff --git a/src/gnu/trove/procedure/TObjectLongProcedure.java b/src/gnu/trove/procedure/TObjectLongProcedure.java new file mode 100644 index 0000000..3e23e67 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type Object and long. + */ +public interface TObjectLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, long b ); +} diff --git a/src/gnu/trove/procedure/TObjectObjectProcedure.java b/src/gnu/trove/procedure/TObjectObjectProcedure.java new file mode 100644 index 0000000..946a623 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectObjectProcedure.java @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +/** + * Interface for procedures that take two Object parameters. + *

+ * Created: Mon Nov 5 22:03:30 2001 + * + * @author Eric D. Friedman + * @version $Id: TObjectObjectProcedure.java,v 1.1.2.1 2009/09/06 17:02:20 upholderoftruth Exp $ + */ + +public interface TObjectObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, V b ); +}// TObjectObjectProcedure diff --git a/src/gnu/trove/procedure/TObjectProcedure.java b/src/gnu/trove/procedure/TObjectProcedure.java new file mode 100644 index 0000000..71cf0e2 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.procedure; + +/** + * Interface for procedures with one Object parameter. + * + * Created: Mon Nov 5 21:45:49 2001 + * + * @author Eric D. Friedman + * @version $Id: TObjectProcedure.java,v 1.1.2.1 2009/09/02 21:52:33 upholderoftruth Exp $ + */ + +public interface TObjectProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param object an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute(T object); +}// TObjectProcedure diff --git a/src/gnu/trove/procedure/TObjectShortProcedure.java b/src/gnu/trove/procedure/TObjectShortProcedure.java new file mode 100644 index 0000000..679ebd2 --- /dev/null +++ b/src/gnu/trove/procedure/TObjectShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type Object and short. + */ +public interface TObjectShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a an Object value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( K a, short b ); +} diff --git a/src/gnu/trove/procedure/TShortByteProcedure.java b/src/gnu/trove/procedure/TShortByteProcedure.java new file mode 100644 index 0000000..9c68276 --- /dev/null +++ b/src/gnu/trove/procedure/TShortByteProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and byte. + */ +public interface TShortByteProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b a byte value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, byte b ); +} diff --git a/src/gnu/trove/procedure/TShortCharProcedure.java b/src/gnu/trove/procedure/TShortCharProcedure.java new file mode 100644 index 0000000..deeaf26 --- /dev/null +++ b/src/gnu/trove/procedure/TShortCharProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and char. + */ +public interface TShortCharProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b a char value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, char b ); +} diff --git a/src/gnu/trove/procedure/TShortDoubleProcedure.java b/src/gnu/trove/procedure/TShortDoubleProcedure.java new file mode 100644 index 0000000..59b2766 --- /dev/null +++ b/src/gnu/trove/procedure/TShortDoubleProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and double. + */ +public interface TShortDoubleProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b a double value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, double b ); +} diff --git a/src/gnu/trove/procedure/TShortFloatProcedure.java b/src/gnu/trove/procedure/TShortFloatProcedure.java new file mode 100644 index 0000000..7cab270 --- /dev/null +++ b/src/gnu/trove/procedure/TShortFloatProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and float. + */ +public interface TShortFloatProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b a float value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, float b ); +} diff --git a/src/gnu/trove/procedure/TShortIntProcedure.java b/src/gnu/trove/procedure/TShortIntProcedure.java new file mode 100644 index 0000000..b4e5251 --- /dev/null +++ b/src/gnu/trove/procedure/TShortIntProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and int. + */ +public interface TShortIntProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b a int value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, int b ); +} diff --git a/src/gnu/trove/procedure/TShortLongProcedure.java b/src/gnu/trove/procedure/TShortLongProcedure.java new file mode 100644 index 0000000..fa52373 --- /dev/null +++ b/src/gnu/trove/procedure/TShortLongProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and long. + */ +public interface TShortLongProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b a long value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, long b ); +} diff --git a/src/gnu/trove/procedure/TShortObjectProcedure.java b/src/gnu/trove/procedure/TShortObjectProcedure.java new file mode 100644 index 0000000..1f72460 --- /dev/null +++ b/src/gnu/trove/procedure/TShortObjectProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and Object. + */ +public interface TShortObjectProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b an Object value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, T b ); +} diff --git a/src/gnu/trove/procedure/TShortProcedure.java b/src/gnu/trove/procedure/TShortProcedure.java new file mode 100644 index 0000000..ebac66c --- /dev/null +++ b/src/gnu/trove/procedure/TShortProcedure.java @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures with one short parameter. + */ +public interface TShortProcedure { + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type short + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short value ); +} diff --git a/src/gnu/trove/procedure/TShortShortProcedure.java b/src/gnu/trove/procedure/TShortShortProcedure.java new file mode 100644 index 0000000..3c59a91 --- /dev/null +++ b/src/gnu/trove/procedure/TShortShortProcedure.java @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * Interface for procedures that take two parameters of type short and short. + */ +public interface TShortShortProcedure { + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param a a short value + * @param b a short value + * @return true if additional invocations of the procedure are + * allowed. + */ + public boolean execute( short a, short b ); +} diff --git a/src/gnu/trove/procedure/array/ToObjectArrayProceedure.java b/src/gnu/trove/procedure/array/ToObjectArrayProceedure.java new file mode 100644 index 0000000..122d23d --- /dev/null +++ b/src/gnu/trove/procedure/array/ToObjectArrayProceedure.java @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.procedure.array; + +import gnu.trove.procedure.TObjectProcedure; + + + +/** + * A procedure which stores each value it receives into a target array. + *

+ * Created: Sat Jan 12 10:13:42 2002 + * + * @author Eric D. Friedman + * @version $Id: ToObjectArrayProceedure.java,v 1.1.2.1 2009/09/02 21:52:33 upholderoftruth Exp $ + */ + +public final class ToObjectArrayProceedure implements TObjectProcedure { + + private final T[] target; + private int pos = 0; + + + public ToObjectArrayProceedure( final T[] target ) { + this.target = target; + } + + + public final boolean execute( T value ) { + target[pos++] = value; + return true; + } +} // ToObjectArrayProcedure \ No newline at end of file diff --git a/src/gnu/trove/queue/TByteQueue.java b/src/gnu/trove/queue/TByteQueue.java new file mode 100644 index 0000000..dc36a1e --- /dev/null +++ b/src/gnu/trove/queue/TByteQueue.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.queue; + + +import gnu.trove.TByteCollection; + +/** + * Interface for Trove queue implementations. + * + * @see java.util.Queue + */ +public interface TByteQueue extends TByteCollection { + /** + * Retrieves and removes the head of this queue. This method differs from + * {@link #poll} only in that it throws an exception if this queue is empty. + */ + public byte element(); + + + /** + * Inserts the specified element into this queue if it is possible to do so + * immediately without violating capacity restrictions. When using a + * capacity-restricted queue, this method is generally preferable to + * {@link #add}, which can fail to insert an element only by throwing an exception. + * + * @param e The element to add. + * + * @return true if the element was added to this queue, else false + */ + public boolean offer( byte e ); + + + /** + * Retrieves, but does not remove, the head of this queue, or returns + * {@link #getNoEntryValue} if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public byte peek(); + + + /** + * Retrieves and removes the head of this queue, or returns {@link #getNoEntryValue} + * if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public byte poll(); +} diff --git a/src/gnu/trove/queue/TCharQueue.java b/src/gnu/trove/queue/TCharQueue.java new file mode 100644 index 0000000..a5c94e8 --- /dev/null +++ b/src/gnu/trove/queue/TCharQueue.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.queue; + + +import gnu.trove.TCharCollection; + +/** + * Interface for Trove queue implementations. + * + * @see java.util.Queue + */ +public interface TCharQueue extends TCharCollection { + /** + * Retrieves and removes the head of this queue. This method differs from + * {@link #poll} only in that it throws an exception if this queue is empty. + */ + public char element(); + + + /** + * Inserts the specified element into this queue if it is possible to do so + * immediately without violating capacity restrictions. When using a + * capacity-restricted queue, this method is generally preferable to + * {@link #add}, which can fail to insert an element only by throwing an exception. + * + * @param e The element to add. + * + * @return true if the element was added to this queue, else false + */ + public boolean offer( char e ); + + + /** + * Retrieves, but does not remove, the head of this queue, or returns + * {@link #getNoEntryValue} if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public char peek(); + + + /** + * Retrieves and removes the head of this queue, or returns {@link #getNoEntryValue} + * if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public char poll(); +} diff --git a/src/gnu/trove/queue/TDoubleQueue.java b/src/gnu/trove/queue/TDoubleQueue.java new file mode 100644 index 0000000..a293fdf --- /dev/null +++ b/src/gnu/trove/queue/TDoubleQueue.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.queue; + + +import gnu.trove.TDoubleCollection; + +/** + * Interface for Trove queue implementations. + * + * @see java.util.Queue + */ +public interface TDoubleQueue extends TDoubleCollection { + /** + * Retrieves and removes the head of this queue. This method differs from + * {@link #poll} only in that it throws an exception if this queue is empty. + */ + public double element(); + + + /** + * Inserts the specified element into this queue if it is possible to do so + * immediately without violating capacity restrictions. When using a + * capacity-restricted queue, this method is generally preferable to + * {@link #add}, which can fail to insert an element only by throwing an exception. + * + * @param e The element to add. + * + * @return true if the element was added to this queue, else false + */ + public boolean offer( double e ); + + + /** + * Retrieves, but does not remove, the head of this queue, or returns + * {@link #getNoEntryValue} if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public double peek(); + + + /** + * Retrieves and removes the head of this queue, or returns {@link #getNoEntryValue} + * if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public double poll(); +} diff --git a/src/gnu/trove/queue/TFloatQueue.java b/src/gnu/trove/queue/TFloatQueue.java new file mode 100644 index 0000000..6dce224 --- /dev/null +++ b/src/gnu/trove/queue/TFloatQueue.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.queue; + + +import gnu.trove.TFloatCollection; + +/** + * Interface for Trove queue implementations. + * + * @see java.util.Queue + */ +public interface TFloatQueue extends TFloatCollection { + /** + * Retrieves and removes the head of this queue. This method differs from + * {@link #poll} only in that it throws an exception if this queue is empty. + */ + public float element(); + + + /** + * Inserts the specified element into this queue if it is possible to do so + * immediately without violating capacity restrictions. When using a + * capacity-restricted queue, this method is generally preferable to + * {@link #add}, which can fail to insert an element only by throwing an exception. + * + * @param e The element to add. + * + * @return true if the element was added to this queue, else false + */ + public boolean offer( float e ); + + + /** + * Retrieves, but does not remove, the head of this queue, or returns + * {@link #getNoEntryValue} if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public float peek(); + + + /** + * Retrieves and removes the head of this queue, or returns {@link #getNoEntryValue} + * if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public float poll(); +} diff --git a/src/gnu/trove/queue/TIntQueue.java b/src/gnu/trove/queue/TIntQueue.java new file mode 100644 index 0000000..5c806f8 --- /dev/null +++ b/src/gnu/trove/queue/TIntQueue.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.queue; + + +import gnu.trove.TIntCollection; + +/** + * Interface for Trove queue implementations. + * + * @see java.util.Queue + */ +public interface TIntQueue extends TIntCollection { + /** + * Retrieves and removes the head of this queue. This method differs from + * {@link #poll} only in that it throws an exception if this queue is empty. + */ + public int element(); + + + /** + * Inserts the specified element into this queue if it is possible to do so + * immediately without violating capacity restrictions. When using a + * capacity-restricted queue, this method is generally preferable to + * {@link #add}, which can fail to insert an element only by throwing an exception. + * + * @param e The element to add. + * + * @return true if the element was added to this queue, else false + */ + public boolean offer( int e ); + + + /** + * Retrieves, but does not remove, the head of this queue, or returns + * {@link #getNoEntryValue} if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public int peek(); + + + /** + * Retrieves and removes the head of this queue, or returns {@link #getNoEntryValue} + * if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public int poll(); +} diff --git a/src/gnu/trove/queue/TLongQueue.java b/src/gnu/trove/queue/TLongQueue.java new file mode 100644 index 0000000..89d60d5 --- /dev/null +++ b/src/gnu/trove/queue/TLongQueue.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.queue; + + +import gnu.trove.TLongCollection; + +/** + * Interface for Trove queue implementations. + * + * @see java.util.Queue + */ +public interface TLongQueue extends TLongCollection { + /** + * Retrieves and removes the head of this queue. This method differs from + * {@link #poll} only in that it throws an exception if this queue is empty. + */ + public long element(); + + + /** + * Inserts the specified element into this queue if it is possible to do so + * immediately without violating capacity restrictions. When using a + * capacity-restricted queue, this method is generally preferable to + * {@link #add}, which can fail to insert an element only by throwing an exception. + * + * @param e The element to add. + * + * @return true if the element was added to this queue, else false + */ + public boolean offer( long e ); + + + /** + * Retrieves, but does not remove, the head of this queue, or returns + * {@link #getNoEntryValue} if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public long peek(); + + + /** + * Retrieves and removes the head of this queue, or returns {@link #getNoEntryValue} + * if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public long poll(); +} diff --git a/src/gnu/trove/queue/TShortQueue.java b/src/gnu/trove/queue/TShortQueue.java new file mode 100644 index 0000000..61a74e1 --- /dev/null +++ b/src/gnu/trove/queue/TShortQueue.java @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.queue; + + +import gnu.trove.TShortCollection; + +/** + * Interface for Trove queue implementations. + * + * @see java.util.Queue + */ +public interface TShortQueue extends TShortCollection { + /** + * Retrieves and removes the head of this queue. This method differs from + * {@link #poll} only in that it throws an exception if this queue is empty. + */ + public short element(); + + + /** + * Inserts the specified element into this queue if it is possible to do so + * immediately without violating capacity restrictions. When using a + * capacity-restricted queue, this method is generally preferable to + * {@link #add}, which can fail to insert an element only by throwing an exception. + * + * @param e The element to add. + * + * @return true if the element was added to this queue, else false + */ + public boolean offer( short e ); + + + /** + * Retrieves, but does not remove, the head of this queue, or returns + * {@link #getNoEntryValue} if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public short peek(); + + + /** + * Retrieves and removes the head of this queue, or returns {@link #getNoEntryValue} + * if this queue is empty. + * + * @return the head of this queue, or {@link #getNoEntryValue} if this queue is empty + */ + public short poll(); +} diff --git a/src/gnu/trove/set/TByteSet.java b/src/gnu/trove/set/TByteSet.java new file mode 100644 index 0000000..b003203 --- /dev/null +++ b/src/gnu/trove/set/TByteSet.java @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set; + + +import java.util.Collection; +import java.util.Set; + +import gnu.trove.TByteCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TByteIterator; +import gnu.trove.procedure.TByteProcedure; + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * Created: Sat Nov 3 10:38:17 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $ + */ + +public interface TByteSet extends TByteCollection { + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + byte getNoEntryValue(); + + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this set contains the specified element. + * + * @param entry an byte value + * @return true if the set contains the specified element. + */ + boolean contains( byte entry ); + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an TByteIterator value + */ + TByteIterator iterator(); + + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + byte[] toArray(); + + + /** + * Returns an array containing elements in this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this set only if the caller knows that this + * set does not contain any elements representing null.) + * + *

If the native array is smaller than the set size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this set are to be + * stored. + * @return an byte[] containing all the elements in this set + * @throws NullPointerException if the specified array is null + */ + byte[] toArray( byte[] dest ); + + + /** + * Inserts a value into the set. + * + * @param entry a byte value + * @return true if the set was modified by the add operation + */ + boolean add( byte entry ); + + + /** + * Removes entry from the set. + * + * @param entry an byte value + * @return true if the set was modified by the remove operation. + */ + boolean remove( byte entry ); + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the set to determine if all of the elements in + * TByteCollection are present. + * + * @param collection a TByteCollection value + * @return true if all elements were present in the set. + */ + boolean containsAll( TByteCollection collection ); + + + /** + * Tests the set to determine if all of the elements in + * array are present. + * + * @param array as array of byte primitives. + * @return true if all elements were present in the set. + */ + boolean containsAll( byte[] array ); + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TByteCollection to the set. + * + * @param collection a TByteCollection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( TByteCollection collection ); + + + /** + * Adds all of the elements in the array to the set. + * + * @param array a array of byte primitives. + * @return true if the set was modified by the add all operation. + */ + boolean addAll( byte[] array ); + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the set which are not contained in + * TByteCollection. + * + * @param collection a TByteCollection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( TByteCollection collection ); + + + /** + * Removes any values in the set which are not contained in + * array. + * + * @param array an array of byte primitives. + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( byte[] array ); + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TByteCollection from the set. + * + * @param collection a TByteCollection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( TByteCollection collection ); + + + /** + * Removes all of the elements in array from the set. + * + * @param array an array of byte primitives. + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( byte[] array ); + + + /** + * Empties the set. + */ + void clear(); + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TByteProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + boolean forEach( TByteProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals( Object o ); + + + /** + * 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. + * 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}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + +} // THashSet diff --git a/src/gnu/trove/set/TCharSet.java b/src/gnu/trove/set/TCharSet.java new file mode 100644 index 0000000..5991f96 --- /dev/null +++ b/src/gnu/trove/set/TCharSet.java @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set; + + +import java.util.Collection; +import java.util.Set; + +import gnu.trove.TCharCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TCharIterator; +import gnu.trove.procedure.TCharProcedure; + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * Created: Sat Nov 3 10:38:17 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $ + */ + +public interface TCharSet extends TCharCollection { + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + char getNoEntryValue(); + + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this set contains the specified element. + * + * @param entry an char value + * @return true if the set contains the specified element. + */ + boolean contains( char entry ); + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an TCharIterator value + */ + TCharIterator iterator(); + + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + char[] toArray(); + + + /** + * Returns an array containing elements in this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this set only if the caller knows that this + * set does not contain any elements representing null.) + * + *

If the native array is smaller than the set size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this set are to be + * stored. + * @return an char[] containing all the elements in this set + * @throws NullPointerException if the specified array is null + */ + char[] toArray( char[] dest ); + + + /** + * Inserts a value into the set. + * + * @param entry a char value + * @return true if the set was modified by the add operation + */ + boolean add( char entry ); + + + /** + * Removes entry from the set. + * + * @param entry an char value + * @return true if the set was modified by the remove operation. + */ + boolean remove( char entry ); + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the set to determine if all of the elements in + * TCharCollection are present. + * + * @param collection a TCharCollection value + * @return true if all elements were present in the set. + */ + boolean containsAll( TCharCollection collection ); + + + /** + * Tests the set to determine if all of the elements in + * array are present. + * + * @param array as array of char primitives. + * @return true if all elements were present in the set. + */ + boolean containsAll( char[] array ); + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TCharCollection to the set. + * + * @param collection a TCharCollection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( TCharCollection collection ); + + + /** + * Adds all of the elements in the array to the set. + * + * @param array a array of char primitives. + * @return true if the set was modified by the add all operation. + */ + boolean addAll( char[] array ); + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the set which are not contained in + * TCharCollection. + * + * @param collection a TCharCollection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( TCharCollection collection ); + + + /** + * Removes any values in the set which are not contained in + * array. + * + * @param array an array of char primitives. + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( char[] array ); + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TCharCollection from the set. + * + * @param collection a TCharCollection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( TCharCollection collection ); + + + /** + * Removes all of the elements in array from the set. + * + * @param array an array of char primitives. + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( char[] array ); + + + /** + * Empties the set. + */ + void clear(); + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TCharProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + boolean forEach( TCharProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals( Object o ); + + + /** + * 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. + * 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}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + +} // THashSet diff --git a/src/gnu/trove/set/TDoubleSet.java b/src/gnu/trove/set/TDoubleSet.java new file mode 100644 index 0000000..9dee178 --- /dev/null +++ b/src/gnu/trove/set/TDoubleSet.java @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set; + + +import java.util.Collection; +import java.util.Set; + +import gnu.trove.TDoubleCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.procedure.TDoubleProcedure; + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * Created: Sat Nov 3 10:38:17 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $ + */ + +public interface TDoubleSet extends TDoubleCollection { + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + double getNoEntryValue(); + + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this set contains the specified element. + * + * @param entry an double value + * @return true if the set contains the specified element. + */ + boolean contains( double entry ); + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an TDoubleIterator value + */ + TDoubleIterator iterator(); + + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + double[] toArray(); + + + /** + * Returns an array containing elements in this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this set only if the caller knows that this + * set does not contain any elements representing null.) + * + *

If the native array is smaller than the set size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this set are to be + * stored. + * @return an double[] containing all the elements in this set + * @throws NullPointerException if the specified array is null + */ + double[] toArray( double[] dest ); + + + /** + * Inserts a value into the set. + * + * @param entry a double value + * @return true if the set was modified by the add operation + */ + boolean add( double entry ); + + + /** + * Removes entry from the set. + * + * @param entry an double value + * @return true if the set was modified by the remove operation. + */ + boolean remove( double entry ); + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the set to determine if all of the elements in + * TDoubleCollection are present. + * + * @param collection a TDoubleCollection value + * @return true if all elements were present in the set. + */ + boolean containsAll( TDoubleCollection collection ); + + + /** + * Tests the set to determine if all of the elements in + * array are present. + * + * @param array as array of double primitives. + * @return true if all elements were present in the set. + */ + boolean containsAll( double[] array ); + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TDoubleCollection to the set. + * + * @param collection a TDoubleCollection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( TDoubleCollection collection ); + + + /** + * Adds all of the elements in the array to the set. + * + * @param array a array of double primitives. + * @return true if the set was modified by the add all operation. + */ + boolean addAll( double[] array ); + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the set which are not contained in + * TDoubleCollection. + * + * @param collection a TDoubleCollection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( TDoubleCollection collection ); + + + /** + * Removes any values in the set which are not contained in + * array. + * + * @param array an array of double primitives. + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( double[] array ); + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TDoubleCollection from the set. + * + * @param collection a TDoubleCollection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( TDoubleCollection collection ); + + + /** + * Removes all of the elements in array from the set. + * + * @param array an array of double primitives. + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( double[] array ); + + + /** + * Empties the set. + */ + void clear(); + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TDoubleProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + boolean forEach( TDoubleProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals( Object o ); + + + /** + * 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. + * 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}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + +} // THashSet diff --git a/src/gnu/trove/set/TFloatSet.java b/src/gnu/trove/set/TFloatSet.java new file mode 100644 index 0000000..6c60c32 --- /dev/null +++ b/src/gnu/trove/set/TFloatSet.java @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set; + + +import java.util.Collection; +import java.util.Set; + +import gnu.trove.TFloatCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.procedure.TFloatProcedure; + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * Created: Sat Nov 3 10:38:17 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $ + */ + +public interface TFloatSet extends TFloatCollection { + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + float getNoEntryValue(); + + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this set contains the specified element. + * + * @param entry an float value + * @return true if the set contains the specified element. + */ + boolean contains( float entry ); + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an TFloatIterator value + */ + TFloatIterator iterator(); + + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + float[] toArray(); + + + /** + * Returns an array containing elements in this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this set only if the caller knows that this + * set does not contain any elements representing null.) + * + *

If the native array is smaller than the set size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this set are to be + * stored. + * @return an float[] containing all the elements in this set + * @throws NullPointerException if the specified array is null + */ + float[] toArray( float[] dest ); + + + /** + * Inserts a value into the set. + * + * @param entry a float value + * @return true if the set was modified by the add operation + */ + boolean add( float entry ); + + + /** + * Removes entry from the set. + * + * @param entry an float value + * @return true if the set was modified by the remove operation. + */ + boolean remove( float entry ); + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the set to determine if all of the elements in + * TFloatCollection are present. + * + * @param collection a TFloatCollection value + * @return true if all elements were present in the set. + */ + boolean containsAll( TFloatCollection collection ); + + + /** + * Tests the set to determine if all of the elements in + * array are present. + * + * @param array as array of float primitives. + * @return true if all elements were present in the set. + */ + boolean containsAll( float[] array ); + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TFloatCollection to the set. + * + * @param collection a TFloatCollection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( TFloatCollection collection ); + + + /** + * Adds all of the elements in the array to the set. + * + * @param array a array of float primitives. + * @return true if the set was modified by the add all operation. + */ + boolean addAll( float[] array ); + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the set which are not contained in + * TFloatCollection. + * + * @param collection a TFloatCollection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( TFloatCollection collection ); + + + /** + * Removes any values in the set which are not contained in + * array. + * + * @param array an array of float primitives. + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( float[] array ); + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TFloatCollection from the set. + * + * @param collection a TFloatCollection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( TFloatCollection collection ); + + + /** + * Removes all of the elements in array from the set. + * + * @param array an array of float primitives. + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( float[] array ); + + + /** + * Empties the set. + */ + void clear(); + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TFloatProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + boolean forEach( TFloatProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals( Object o ); + + + /** + * 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. + * 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}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + +} // THashSet diff --git a/src/gnu/trove/set/TIntSet.java b/src/gnu/trove/set/TIntSet.java new file mode 100644 index 0000000..f0fd8a4 --- /dev/null +++ b/src/gnu/trove/set/TIntSet.java @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set; + + +import java.util.Collection; +import java.util.Set; + +import gnu.trove.TIntCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TIntIterator; +import gnu.trove.procedure.TIntProcedure; + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * Created: Sat Nov 3 10:38:17 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $ + */ + +public interface TIntSet extends TIntCollection { + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + int getNoEntryValue(); + + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this set contains the specified element. + * + * @param entry an int value + * @return true if the set contains the specified element. + */ + boolean contains( int entry ); + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an TIntIterator value + */ + TIntIterator iterator(); + + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + int[] toArray(); + + + /** + * Returns an array containing elements in this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this set only if the caller knows that this + * set does not contain any elements representing null.) + * + *

If the native array is smaller than the set size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this set are to be + * stored. + * @return an int[] containing all the elements in this set + * @throws NullPointerException if the specified array is null + */ + int[] toArray( int[] dest ); + + + /** + * Inserts a value into the set. + * + * @param entry a int value + * @return true if the set was modified by the add operation + */ + boolean add( int entry ); + + + /** + * Removes entry from the set. + * + * @param entry an int value + * @return true if the set was modified by the remove operation. + */ + boolean remove( int entry ); + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the set to determine if all of the elements in + * TIntCollection are present. + * + * @param collection a TIntCollection value + * @return true if all elements were present in the set. + */ + boolean containsAll( TIntCollection collection ); + + + /** + * Tests the set to determine if all of the elements in + * array are present. + * + * @param array as array of int primitives. + * @return true if all elements were present in the set. + */ + boolean containsAll( int[] array ); + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TIntCollection to the set. + * + * @param collection a TIntCollection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( TIntCollection collection ); + + + /** + * Adds all of the elements in the array to the set. + * + * @param array a array of int primitives. + * @return true if the set was modified by the add all operation. + */ + boolean addAll( int[] array ); + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the set which are not contained in + * TIntCollection. + * + * @param collection a TIntCollection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( TIntCollection collection ); + + + /** + * Removes any values in the set which are not contained in + * array. + * + * @param array an array of int primitives. + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( int[] array ); + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TIntCollection from the set. + * + * @param collection a TIntCollection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( TIntCollection collection ); + + + /** + * Removes all of the elements in array from the set. + * + * @param array an array of int primitives. + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( int[] array ); + + + /** + * Empties the set. + */ + void clear(); + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TIntProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + boolean forEach( TIntProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals( Object o ); + + + /** + * 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. + * 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}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + +} // THashSet diff --git a/src/gnu/trove/set/TLongSet.java b/src/gnu/trove/set/TLongSet.java new file mode 100644 index 0000000..0364961 --- /dev/null +++ b/src/gnu/trove/set/TLongSet.java @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set; + + +import java.util.Collection; +import java.util.Set; + +import gnu.trove.TLongCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TLongIterator; +import gnu.trove.procedure.TLongProcedure; + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * Created: Sat Nov 3 10:38:17 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $ + */ + +public interface TLongSet extends TLongCollection { + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + long getNoEntryValue(); + + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this set contains the specified element. + * + * @param entry an long value + * @return true if the set contains the specified element. + */ + boolean contains( long entry ); + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an TLongIterator value + */ + TLongIterator iterator(); + + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + long[] toArray(); + + + /** + * Returns an array containing elements in this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this set only if the caller knows that this + * set does not contain any elements representing null.) + * + *

If the native array is smaller than the set size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this set are to be + * stored. + * @return an long[] containing all the elements in this set + * @throws NullPointerException if the specified array is null + */ + long[] toArray( long[] dest ); + + + /** + * Inserts a value into the set. + * + * @param entry a long value + * @return true if the set was modified by the add operation + */ + boolean add( long entry ); + + + /** + * Removes entry from the set. + * + * @param entry an long value + * @return true if the set was modified by the remove operation. + */ + boolean remove( long entry ); + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the set to determine if all of the elements in + * TLongCollection are present. + * + * @param collection a TLongCollection value + * @return true if all elements were present in the set. + */ + boolean containsAll( TLongCollection collection ); + + + /** + * Tests the set to determine if all of the elements in + * array are present. + * + * @param array as array of long primitives. + * @return true if all elements were present in the set. + */ + boolean containsAll( long[] array ); + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TLongCollection to the set. + * + * @param collection a TLongCollection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( TLongCollection collection ); + + + /** + * Adds all of the elements in the array to the set. + * + * @param array a array of long primitives. + * @return true if the set was modified by the add all operation. + */ + boolean addAll( long[] array ); + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the set which are not contained in + * TLongCollection. + * + * @param collection a TLongCollection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( TLongCollection collection ); + + + /** + * Removes any values in the set which are not contained in + * array. + * + * @param array an array of long primitives. + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( long[] array ); + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TLongCollection from the set. + * + * @param collection a TLongCollection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( TLongCollection collection ); + + + /** + * Removes all of the elements in array from the set. + * + * @param array an array of long primitives. + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( long[] array ); + + + /** + * Empties the set. + */ + void clear(); + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TLongProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + boolean forEach( TLongProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals( Object o ); + + + /** + * 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. + * 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}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + +} // THashSet diff --git a/src/gnu/trove/set/TShortSet.java b/src/gnu/trove/set/TShortSet.java new file mode 100644 index 0000000..b3031ae --- /dev/null +++ b/src/gnu/trove/set/TShortSet.java @@ -0,0 +1,320 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set; + + +import java.util.Collection; +import java.util.Set; + +import gnu.trove.TShortCollection; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + +import gnu.trove.iterator.TShortIterator; +import gnu.trove.procedure.TShortProcedure; + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * Created: Sat Nov 3 10:38:17 2001 + * + * @author Eric D. Friedman, Rob Eden, Jeff Randall + * @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $ + */ + +public interface TShortSet extends TShortCollection { + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + short getNoEntryValue(); + + + /** + * Returns the number of elements in this set (its cardinality). If this + * set contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this set (its cardinality) + */ + int size(); + + + /** + * Returns true if this set contains no elements. + * + * @return true if this set contains no elements + */ + boolean isEmpty(); + + + /** + * Returns true if this set contains the specified element. + * + * @param entry an short value + * @return true if the set contains the specified element. + */ + boolean contains( short entry ); + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an TShortIterator value + */ + TShortIterator iterator(); + + + /** + * Returns an array containing all of the elements in this set. + * If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the + * elements in the same order. + * + *

The returned array will be "safe" in that no references to it + * are maintained by this set. (In other words, this method must + * allocate a new array even if this set is backed by an array). + * The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all the elements in this set + */ + short[] toArray(); + + + /** + * Returns an array containing elements in this set. + * + *

If this set fits in the specified array with room to spare + * (i.e., the array has more elements than this set), the element in + * the array immediately following the end of the set is set to + * {@link #getNoEntryValue()}. (This is useful in determining + * the length of this set only if the caller knows that this + * set does not contain any elements representing null.) + * + *

If the native array is smaller than the set size, + * the array will be filled with elements in Iterator order + * until it is full and exclude the remainder. + * + *

If this set makes any guarantees as to what order its elements + * are returned by its iterator, this method must return the elements + * in the same order. + * + * @param dest the array into which the elements of this set are to be + * stored. + * @return an short[] containing all the elements in this set + * @throws NullPointerException if the specified array is null + */ + short[] toArray( short[] dest ); + + + /** + * Inserts a value into the set. + * + * @param entry a short value + * @return true if the set was modified by the add operation + */ + boolean add( short entry ); + + + /** + * Removes entry from the set. + * + * @param entry an short value + * @return true if the set was modified by the remove operation. + */ + boolean remove( short entry ); + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + boolean containsAll( Collection collection ); + + + /** + * Tests the set to determine if all of the elements in + * TShortCollection are present. + * + * @param collection a TShortCollection value + * @return true if all elements were present in the set. + */ + boolean containsAll( TShortCollection collection ); + + + /** + * Tests the set to determine if all of the elements in + * array are present. + * + * @param array as array of short primitives. + * @return true if all elements were present in the set. + */ + boolean containsAll( short[] array ); + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( Collection collection ); + + + /** + * Adds all of the elements in the TShortCollection to the set. + * + * @param collection a TShortCollection value + * @return true if the set was modified by the add all operation. + */ + boolean addAll( TShortCollection collection ); + + + /** + * Adds all of the elements in the array to the set. + * + * @param array a array of short primitives. + * @return true if the set was modified by the add all operation. + */ + boolean addAll( short[] array ); + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( Collection collection ); + + + /** + * Removes any values in the set which are not contained in + * TShortCollection. + * + * @param collection a TShortCollection value + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( TShortCollection collection ); + + + /** + * Removes any values in the set which are not contained in + * array. + * + * @param array an array of short primitives. + * @return true if the set was modified by the retain all operation + */ + boolean retainAll( short[] array ); + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( Collection collection ); + + + /** + * Removes all of the elements in TShortCollection from the set. + * + * @param collection a TShortCollection value + * @return true if the set was modified by the remove all operation. + */ + boolean removeAll( TShortCollection collection ); + + + /** + * Removes all of the elements in array from the set. + * + * @param array an array of short primitives. + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( short[] array ); + + + /** + * Empties the set. + */ + void clear(); + + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TShortProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + boolean forEach( TShortProcedure procedure ); + + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the specified object is also a set, the two sets + * have the same size, and every member of the specified set is + * contained in this set (or equivalently, every member of this set is + * contained in the specified set). This definition ensures that the + * equals method works properly across different implementations of the + * set interface. + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + boolean equals( Object o ); + + + /** + * 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. + * 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}. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + int hashCode(); + + +} // THashSet diff --git a/src/gnu/trove/set/hash/TByteHashSet.java b/src/gnu/trove/set/hash/TByteHashSet.java new file mode 100644 index 0000000..3bce685 --- /dev/null +++ b/src/gnu/trove/set/hash/TByteHashSet.java @@ -0,0 +1,555 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.set.TByteSet; +import gnu.trove.iterator.TByteIterator; +import gnu.trove.impl.*; +import gnu.trove.impl.hash.*; +import gnu.trove.TByteCollection; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Externalizable; +import java.util.Arrays; +import java.util.Collection; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed set implementation for byte primitives. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ + +public class TByteHashSet extends TByteHash implements TByteSet, Externalizable { + static final long serialVersionUID = 1L; + + + /** + * Creates a new TByteHashSet instance with the default + * capacity and load factor. + */ + public TByteHashSet() { + super(); + } + + + /** + * Creates a new TByteHashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TByteHashSet( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param load_factor used to calculate the threshold over which + * rehashing takes place. + */ + public TByteHashSet( int initialCapacity, float load_factor ) { + super( initialCapacity, load_factor ); + } + + + /** + * Creates a new TByteHashSet instance with a prime + * capacity equal to or greater than initial_capacity and + * with the specified load factor. + * + * @param initial_capacity an int value + * @param load_factor a float value + * @param no_entry_value a byte value that represents null. + */ + public TByteHashSet( int initial_capacity, float load_factor, + byte no_entry_value ) { + super( initial_capacity, load_factor, no_entry_value ); + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TByteHashSet instance that is a copy + * of the existing Collection. + * + * @param collection a Collection that will be duplicated. + */ + public TByteHashSet( Collection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + addAll( collection ); + } + + + /** + * Creates a new TByteHashSet instance that is a copy + * of the existing set. + * + * @param collection a TByteSet that will be duplicated. + */ + public TByteHashSet( TByteCollection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + if ( collection instanceof TByteHashSet ) { + TByteHashSet hashset = ( TByteHashSet ) collection; + this._loadFactor = hashset._loadFactor; + this.no_entry_value = hashset.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( byte ) 0 ) { + Arrays.fill( _set, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + addAll( collection ); + } + + + /** + * Creates a new TByteHashSet instance containing the + * elements of array. + * + * @param array an array of byte primitives + */ + public TByteHashSet( byte[] array ) { + this( Math.max( array.length, DEFAULT_CAPACITY ) ); + addAll( array ); + } + + + /** {@inheritDoc} */ + public TByteIterator iterator() { + return new TByteHashIterator( this ); + } + + + /** {@inheritDoc} */ + public byte[] toArray() { + byte[] result = new byte[ size() ]; + if ( result.length == 0 ) { + return result; // nothing to copy + } + byte[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + result[j++] = set[i]; + } + } + return result; + } + + + /** {@inheritDoc} */ + public byte[] toArray( byte[] dest ) { + if ( dest.length == 0 ) { + return dest; // nothing to copy + } + byte[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = set[i]; + } + } + + if ( dest.length > _size ) { + dest[_size] = no_entry_value; + } + return dest; + } + + + /** {@inheritDoc} */ + public boolean add( byte val ) { + int index = insertKey(val); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + + return true; // yes, we added something + } + + + /** {@inheritDoc} */ + public boolean remove( byte val ) { + int index = index(val); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TByteCollection collection ) { + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( byte[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Byte element : collection ) { + byte e = element.byteValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TByteCollection collection ) { + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( add( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Byte.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TByteCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TByteIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( byte[] array ) { + boolean changed = false; + Arrays.sort( array ); + byte[] set = _set; + byte[] states = _states; + + _autoCompactTemporaryDisable = true; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + _autoCompactTemporaryDisable = false; + + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Byte ) { + byte c = ( ( Byte ) element ).byteValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TByteCollection collection ) { + boolean changed = false; + TByteIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + byte element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( byte[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + byte[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + set[i] = no_entry_value; + states[i] = FREE; + } + } + + + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + byte oldSet[] = _set; + byte oldStates[] = _states; + + _set = new byte[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + byte o = oldSet[i]; + insertKey(o); + } + } + } + + + /** {@inheritDoc} */ + public boolean equals( Object other ) { + if ( ! ( other instanceof TByteSet ) ) { + return false; + } + TByteSet that = ( TByteSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + public String toString() { + StringBuilder buffy = new StringBuilder( _size * 2 + 2 ); + buffy.append("{"); + for ( int i = _states.length, j = 1; i-- > 0; ) { + if ( _states[i] == FULL ) { + buffy.append( _set[i] ); + if ( j++ < _size ) { + buffy.append( "," ); + } + } + } + buffy.append("}"); + return buffy.toString(); + } + + + class TByteHashIterator extends THashPrimitiveIterator implements TByteIterator { + + /** the collection on which the iterator operates */ + private final TByteHash _hash; + + /** {@inheritDoc} */ + public TByteHashIterator( TByteHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public byte next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 1 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // LOAD FACTOR -- Added version 1 + out.writeFloat( _loadFactor ); + + // NO ENTRY VALUE -- Added version 1 + out.writeByte( no_entry_value ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeByte( _set[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + int version = in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + + if ( version >= 1 ) { + // LOAD FACTOR + _loadFactor = in.readFloat(); + + // NO ENTRY VALUE + no_entry_value = in.readByte(); + //noinspection RedundantCast + if ( no_entry_value != ( byte ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + // ENTRIES + setUp( size ); + while ( size-- > 0 ) { + byte val = in.readByte(); + add( val ); + } + } +} // TIntHashSet diff --git a/src/gnu/trove/set/hash/TCharHashSet.java b/src/gnu/trove/set/hash/TCharHashSet.java new file mode 100644 index 0000000..7fd7c41 --- /dev/null +++ b/src/gnu/trove/set/hash/TCharHashSet.java @@ -0,0 +1,555 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.set.TCharSet; +import gnu.trove.iterator.TCharIterator; +import gnu.trove.impl.*; +import gnu.trove.impl.hash.*; +import gnu.trove.TCharCollection; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Externalizable; +import java.util.Arrays; +import java.util.Collection; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed set implementation for char primitives. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ + +public class TCharHashSet extends TCharHash implements TCharSet, Externalizable { + static final long serialVersionUID = 1L; + + + /** + * Creates a new TCharHashSet instance with the default + * capacity and load factor. + */ + public TCharHashSet() { + super(); + } + + + /** + * Creates a new TCharHashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCharHashSet( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param load_factor used to calculate the threshold over which + * rehashing takes place. + */ + public TCharHashSet( int initialCapacity, float load_factor ) { + super( initialCapacity, load_factor ); + } + + + /** + * Creates a new TCharHashSet instance with a prime + * capacity equal to or greater than initial_capacity and + * with the specified load factor. + * + * @param initial_capacity an int value + * @param load_factor a float value + * @param no_entry_value a char value that represents null. + */ + public TCharHashSet( int initial_capacity, float load_factor, + char no_entry_value ) { + super( initial_capacity, load_factor, no_entry_value ); + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TCharHashSet instance that is a copy + * of the existing Collection. + * + * @param collection a Collection that will be duplicated. + */ + public TCharHashSet( Collection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + addAll( collection ); + } + + + /** + * Creates a new TCharHashSet instance that is a copy + * of the existing set. + * + * @param collection a TCharSet that will be duplicated. + */ + public TCharHashSet( TCharCollection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + if ( collection instanceof TCharHashSet ) { + TCharHashSet hashset = ( TCharHashSet ) collection; + this._loadFactor = hashset._loadFactor; + this.no_entry_value = hashset.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( char ) 0 ) { + Arrays.fill( _set, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + addAll( collection ); + } + + + /** + * Creates a new TCharHashSet instance containing the + * elements of array. + * + * @param array an array of char primitives + */ + public TCharHashSet( char[] array ) { + this( Math.max( array.length, DEFAULT_CAPACITY ) ); + addAll( array ); + } + + + /** {@inheritDoc} */ + public TCharIterator iterator() { + return new TCharHashIterator( this ); + } + + + /** {@inheritDoc} */ + public char[] toArray() { + char[] result = new char[ size() ]; + if ( result.length == 0 ) { + return result; // nothing to copy + } + char[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + result[j++] = set[i]; + } + } + return result; + } + + + /** {@inheritDoc} */ + public char[] toArray( char[] dest ) { + if ( dest.length == 0 ) { + return dest; // nothing to copy + } + char[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = set[i]; + } + } + + if ( dest.length > _size ) { + dest[_size] = no_entry_value; + } + return dest; + } + + + /** {@inheritDoc} */ + public boolean add( char val ) { + int index = insertKey(val); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + + return true; // yes, we added something + } + + + /** {@inheritDoc} */ + public boolean remove( char val ) { + int index = index(val); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TCharCollection collection ) { + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( char[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Character element : collection ) { + char e = element.charValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TCharCollection collection ) { + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( add( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Character.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TCharCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TCharIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( char[] array ) { + boolean changed = false; + Arrays.sort( array ); + char[] set = _set; + byte[] states = _states; + + _autoCompactTemporaryDisable = true; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + _autoCompactTemporaryDisable = false; + + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Character ) { + char c = ( ( Character ) element ).charValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TCharCollection collection ) { + boolean changed = false; + TCharIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + char element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( char[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + char[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + set[i] = no_entry_value; + states[i] = FREE; + } + } + + + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + char oldSet[] = _set; + byte oldStates[] = _states; + + _set = new char[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + char o = oldSet[i]; + insertKey(o); + } + } + } + + + /** {@inheritDoc} */ + public boolean equals( Object other ) { + if ( ! ( other instanceof TCharSet ) ) { + return false; + } + TCharSet that = ( TCharSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + public String toString() { + StringBuilder buffy = new StringBuilder( _size * 2 + 2 ); + buffy.append("{"); + for ( int i = _states.length, j = 1; i-- > 0; ) { + if ( _states[i] == FULL ) { + buffy.append( _set[i] ); + if ( j++ < _size ) { + buffy.append( "," ); + } + } + } + buffy.append("}"); + return buffy.toString(); + } + + + class TCharHashIterator extends THashPrimitiveIterator implements TCharIterator { + + /** the collection on which the iterator operates */ + private final TCharHash _hash; + + /** {@inheritDoc} */ + public TCharHashIterator( TCharHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public char next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 1 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // LOAD FACTOR -- Added version 1 + out.writeFloat( _loadFactor ); + + // NO ENTRY VALUE -- Added version 1 + out.writeChar( no_entry_value ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeChar( _set[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + int version = in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + + if ( version >= 1 ) { + // LOAD FACTOR + _loadFactor = in.readFloat(); + + // NO ENTRY VALUE + no_entry_value = in.readChar(); + //noinspection RedundantCast + if ( no_entry_value != ( char ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + // ENTRIES + setUp( size ); + while ( size-- > 0 ) { + char val = in.readChar(); + add( val ); + } + } +} // TIntHashSet diff --git a/src/gnu/trove/set/hash/TCustomHashSet.java b/src/gnu/trove/set/hash/TCustomHashSet.java new file mode 100644 index 0000000..b42dce5 --- /dev/null +++ b/src/gnu/trove/set/hash/TCustomHashSet.java @@ -0,0 +1,410 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.strategy.HashingStrategy; +import gnu.trove.impl.HashFunctions; +import gnu.trove.impl.hash.TCustomObjectHash; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.array.ToObjectArrayProceedure; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * @author Rob Eden + */ +public class TCustomHashSet extends TCustomObjectHash + implements Set, Iterable, Externalizable { + + static final long serialVersionUID = 1L; + + + /** FOR EXTERNALIZATION ONLY!!! */ + public TCustomHashSet() {} + + + /** + * Creates a new THashSet instance with the default + * capacity and load factor. + */ + public TCustomHashSet( HashingStrategy strategy ) { + super( strategy ); + } + + + /** + * Creates a new THashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TCustomHashSet( HashingStrategy strategy, int initialCapacity ) { + super( strategy, initialCapacity ); + } + + + /** + * Creates a new THashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TCustomHashSet( HashingStrategy strategy, int initialCapacity, + float loadFactor ) { + + super( strategy, initialCapacity, loadFactor ); + } + + + /** + * Creates a new THashSet instance containing the + * elements of collection. + * + * @param collection a Collection value + */ + public TCustomHashSet( HashingStrategy strategy, + Collection collection ) { + + this( strategy, collection.size() ); + addAll( collection ); + } + + + /** + * Inserts a value into the set. + * + * @param obj an Object value + * @return true if the set was modified by the add operation + */ + public boolean add( E obj ) { + int index = insertKey( obj ); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + return true; // yes, we added something + } + + + @SuppressWarnings({}) + public boolean equals( Object other ) { + if ( !( other instanceof Set ) ) { + return false; + } + Set that = (Set) other; + if ( that.size() != this.size() ) { + return false; + } + return containsAll( that ); + } + + + public int hashCode() { + HashProcedure p = new HashProcedure(); + forEach( p ); + return p.getHashCode(); + } + + + private final class HashProcedure implements TObjectProcedure { + private int h = 0; + + public int getHashCode() { + return h; + } + + public final boolean execute( E key ) { + h += HashFunctions.hash( key ); + return true; + } + } + + + /** + * Expands the set to accommodate new values. + * + * @param newCapacity an int value + */ + @SuppressWarnings({"unchecked"}) + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + int oldSize = size(); + Object oldSet[] = _set; + + _set = new Object[newCapacity]; + Arrays.fill( _set, FREE ); + + for ( int i = oldCapacity; i-- > 0; ) { + E o = (E) oldSet[i]; + if ( o != FREE && o != REMOVED ) { + int index = insertKey( o ); + if ( index < 0 ) { // everyone pays for this because some people can't RTFM + throwObjectContractViolation( _set[( -index - 1 )], o, size(), oldSize, oldSet); + } + } + } + } + + + /** + * Returns a new array containing the objects in the set. + * + * @return an Object[] value + */ + @SuppressWarnings({}) + public Object[] toArray() { + Object[] result = new Object[size()]; + forEach( new ToObjectArrayProceedure( result ) ); + return result; + } + + + /** + * Returns a typed array of the objects in the set. + * + * @param a an Object[] value + * @return an Object[] value + */ + @SuppressWarnings({"unchecked"}) + public T[] toArray( T[] a ) { + int size = size(); + if ( a.length < size ) { + a = (T[]) Array.newInstance( a.getClass().getComponentType(), size ); + } + + forEach( new ToObjectArrayProceedure( a ) ); + + // If this collection fits in the specified array with room to + // spare (i.e., the array has more elements than this + // collection), the element in the array immediately following + // the end of the collection is set to null. This is useful in + // determining the length of this collection only if the + // caller knows that this collection does not contain any null + // elements.) + + if ( a.length > size ) { + a[size] = null; + } + + return a; + } + + + /** Empties the set. */ + public void clear() { + super.clear(); + + Arrays.fill( _set, 0, _set.length, FREE ); + } + + + /** + * Removes obj from the set. + * + * @param obj an Object value + * @return true if the set was modified by the remove operation. + */ + @SuppressWarnings({}) + public boolean remove( Object obj ) { + int index = index( obj ); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an Iterator value + */ + @SuppressWarnings({}) + public TObjectHashIterator iterator() { + return new TObjectHashIterator( this ); + } + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + public boolean containsAll( Collection collection ) { + for ( Iterator i = collection.iterator(); i.hasNext(); ) { + if ( !contains( i.next() ) ) { + return false; + } + } + return true; + } + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + public boolean addAll( Collection collection ) { + boolean changed = false; + int size = collection.size(); + + ensureCapacity( size ); + Iterator it = collection.iterator(); + while ( size-- > 0 ) { + if ( add( it.next() ) ) { + changed = true; + } + } + return changed; + } + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + int size = collection.size(); + Iterator it; + + it = collection.iterator(); + while ( size-- > 0 ) { + if ( remove( it.next() ) ) { + changed = true; + } + } + return changed; + } + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean changed = false; + int size = size(); + Iterator it = iterator(); + while ( size-- > 0 ) { + if ( !collection.contains( it.next() ) ) { + it.remove(); + changed = true; + } + } + return changed; + } + + + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + forEach( new TObjectProcedure() { + private boolean first = true; + + + public boolean execute( Object value ) { + if ( first ) { + first = false; + } else { + buf.append( ", " ); + } + + buf.append( value ); + return true; + } + } ); + buf.append( "}" ); + return buf.toString(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 1 ); + + // NOTE: Super was not written in version 0 + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // ENTRIES + for ( int i = _set.length; i-- > 0; ) { + if ( _set[i] != REMOVED && _set[i] != FREE ) { + out.writeObject( _set[i] ); + } + } + } + + + @SuppressWarnings({"unchecked"}) + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + byte version = in.readByte(); + + // NOTE: super was not written in version 0 + if ( version != 0 ) { + super.readExternal( in ); + } + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp( size ); + + // ENTRIES + while ( size-- > 0 ) { + E val = (E) in.readObject(); + add( val ); + } + } +} diff --git a/src/gnu/trove/set/hash/TDoubleHashSet.java b/src/gnu/trove/set/hash/TDoubleHashSet.java new file mode 100644 index 0000000..2fde10c --- /dev/null +++ b/src/gnu/trove/set/hash/TDoubleHashSet.java @@ -0,0 +1,555 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.set.TDoubleSet; +import gnu.trove.iterator.TDoubleIterator; +import gnu.trove.impl.*; +import gnu.trove.impl.hash.*; +import gnu.trove.TDoubleCollection; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Externalizable; +import java.util.Arrays; +import java.util.Collection; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed set implementation for double primitives. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ + +public class TDoubleHashSet extends TDoubleHash implements TDoubleSet, Externalizable { + static final long serialVersionUID = 1L; + + + /** + * Creates a new TDoubleHashSet instance with the default + * capacity and load factor. + */ + public TDoubleHashSet() { + super(); + } + + + /** + * Creates a new TDoubleHashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TDoubleHashSet( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param load_factor used to calculate the threshold over which + * rehashing takes place. + */ + public TDoubleHashSet( int initialCapacity, float load_factor ) { + super( initialCapacity, load_factor ); + } + + + /** + * Creates a new TDoubleHashSet instance with a prime + * capacity equal to or greater than initial_capacity and + * with the specified load factor. + * + * @param initial_capacity an int value + * @param load_factor a float value + * @param no_entry_value a double value that represents null. + */ + public TDoubleHashSet( int initial_capacity, float load_factor, + double no_entry_value ) { + super( initial_capacity, load_factor, no_entry_value ); + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TDoubleHashSet instance that is a copy + * of the existing Collection. + * + * @param collection a Collection that will be duplicated. + */ + public TDoubleHashSet( Collection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + addAll( collection ); + } + + + /** + * Creates a new TDoubleHashSet instance that is a copy + * of the existing set. + * + * @param collection a TDoubleSet that will be duplicated. + */ + public TDoubleHashSet( TDoubleCollection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + if ( collection instanceof TDoubleHashSet ) { + TDoubleHashSet hashset = ( TDoubleHashSet ) collection; + this._loadFactor = hashset._loadFactor; + this.no_entry_value = hashset.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( double ) 0 ) { + Arrays.fill( _set, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + addAll( collection ); + } + + + /** + * Creates a new TDoubleHashSet instance containing the + * elements of array. + * + * @param array an array of double primitives + */ + public TDoubleHashSet( double[] array ) { + this( Math.max( array.length, DEFAULT_CAPACITY ) ); + addAll( array ); + } + + + /** {@inheritDoc} */ + public TDoubleIterator iterator() { + return new TDoubleHashIterator( this ); + } + + + /** {@inheritDoc} */ + public double[] toArray() { + double[] result = new double[ size() ]; + if ( result.length == 0 ) { + return result; // nothing to copy + } + double[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + result[j++] = set[i]; + } + } + return result; + } + + + /** {@inheritDoc} */ + public double[] toArray( double[] dest ) { + if ( dest.length == 0 ) { + return dest; // nothing to copy + } + double[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = set[i]; + } + } + + if ( dest.length > _size ) { + dest[_size] = no_entry_value; + } + return dest; + } + + + /** {@inheritDoc} */ + public boolean add( double val ) { + int index = insertKey(val); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + + return true; // yes, we added something + } + + + /** {@inheritDoc} */ + public boolean remove( double val ) { + int index = index(val); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TDoubleCollection collection ) { + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( double[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Double element : collection ) { + double e = element.doubleValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TDoubleCollection collection ) { + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( add( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Double.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TDoubleCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TDoubleIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( double[] array ) { + boolean changed = false; + Arrays.sort( array ); + double[] set = _set; + byte[] states = _states; + + _autoCompactTemporaryDisable = true; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + _autoCompactTemporaryDisable = false; + + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Double ) { + double c = ( ( Double ) element ).doubleValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TDoubleCollection collection ) { + boolean changed = false; + TDoubleIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + double element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( double[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + double[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + set[i] = no_entry_value; + states[i] = FREE; + } + } + + + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + double oldSet[] = _set; + byte oldStates[] = _states; + + _set = new double[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + double o = oldSet[i]; + insertKey(o); + } + } + } + + + /** {@inheritDoc} */ + public boolean equals( Object other ) { + if ( ! ( other instanceof TDoubleSet ) ) { + return false; + } + TDoubleSet that = ( TDoubleSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + public String toString() { + StringBuilder buffy = new StringBuilder( _size * 2 + 2 ); + buffy.append("{"); + for ( int i = _states.length, j = 1; i-- > 0; ) { + if ( _states[i] == FULL ) { + buffy.append( _set[i] ); + if ( j++ < _size ) { + buffy.append( "," ); + } + } + } + buffy.append("}"); + return buffy.toString(); + } + + + class TDoubleHashIterator extends THashPrimitiveIterator implements TDoubleIterator { + + /** the collection on which the iterator operates */ + private final TDoubleHash _hash; + + /** {@inheritDoc} */ + public TDoubleHashIterator( TDoubleHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public double next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 1 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // LOAD FACTOR -- Added version 1 + out.writeFloat( _loadFactor ); + + // NO ENTRY VALUE -- Added version 1 + out.writeDouble( no_entry_value ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeDouble( _set[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + int version = in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + + if ( version >= 1 ) { + // LOAD FACTOR + _loadFactor = in.readFloat(); + + // NO ENTRY VALUE + no_entry_value = in.readDouble(); + //noinspection RedundantCast + if ( no_entry_value != ( double ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + // ENTRIES + setUp( size ); + while ( size-- > 0 ) { + double val = in.readDouble(); + add( val ); + } + } +} // TIntHashSet diff --git a/src/gnu/trove/set/hash/TFloatHashSet.java b/src/gnu/trove/set/hash/TFloatHashSet.java new file mode 100644 index 0000000..8515c3a --- /dev/null +++ b/src/gnu/trove/set/hash/TFloatHashSet.java @@ -0,0 +1,555 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.set.TFloatSet; +import gnu.trove.iterator.TFloatIterator; +import gnu.trove.impl.*; +import gnu.trove.impl.hash.*; +import gnu.trove.TFloatCollection; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Externalizable; +import java.util.Arrays; +import java.util.Collection; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed set implementation for float primitives. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ + +public class TFloatHashSet extends TFloatHash implements TFloatSet, Externalizable { + static final long serialVersionUID = 1L; + + + /** + * Creates a new TFloatHashSet instance with the default + * capacity and load factor. + */ + public TFloatHashSet() { + super(); + } + + + /** + * Creates a new TFloatHashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TFloatHashSet( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param load_factor used to calculate the threshold over which + * rehashing takes place. + */ + public TFloatHashSet( int initialCapacity, float load_factor ) { + super( initialCapacity, load_factor ); + } + + + /** + * Creates a new TFloatHashSet instance with a prime + * capacity equal to or greater than initial_capacity and + * with the specified load factor. + * + * @param initial_capacity an int value + * @param load_factor a float value + * @param no_entry_value a float value that represents null. + */ + public TFloatHashSet( int initial_capacity, float load_factor, + float no_entry_value ) { + super( initial_capacity, load_factor, no_entry_value ); + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TFloatHashSet instance that is a copy + * of the existing Collection. + * + * @param collection a Collection that will be duplicated. + */ + public TFloatHashSet( Collection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + addAll( collection ); + } + + + /** + * Creates a new TFloatHashSet instance that is a copy + * of the existing set. + * + * @param collection a TFloatSet that will be duplicated. + */ + public TFloatHashSet( TFloatCollection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + if ( collection instanceof TFloatHashSet ) { + TFloatHashSet hashset = ( TFloatHashSet ) collection; + this._loadFactor = hashset._loadFactor; + this.no_entry_value = hashset.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( float ) 0 ) { + Arrays.fill( _set, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + addAll( collection ); + } + + + /** + * Creates a new TFloatHashSet instance containing the + * elements of array. + * + * @param array an array of float primitives + */ + public TFloatHashSet( float[] array ) { + this( Math.max( array.length, DEFAULT_CAPACITY ) ); + addAll( array ); + } + + + /** {@inheritDoc} */ + public TFloatIterator iterator() { + return new TFloatHashIterator( this ); + } + + + /** {@inheritDoc} */ + public float[] toArray() { + float[] result = new float[ size() ]; + if ( result.length == 0 ) { + return result; // nothing to copy + } + float[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + result[j++] = set[i]; + } + } + return result; + } + + + /** {@inheritDoc} */ + public float[] toArray( float[] dest ) { + if ( dest.length == 0 ) { + return dest; // nothing to copy + } + float[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = set[i]; + } + } + + if ( dest.length > _size ) { + dest[_size] = no_entry_value; + } + return dest; + } + + + /** {@inheritDoc} */ + public boolean add( float val ) { + int index = insertKey(val); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + + return true; // yes, we added something + } + + + /** {@inheritDoc} */ + public boolean remove( float val ) { + int index = index(val); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TFloatCollection collection ) { + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( float[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Float element : collection ) { + float e = element.floatValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TFloatCollection collection ) { + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( add( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Float.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TFloatCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TFloatIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( float[] array ) { + boolean changed = false; + Arrays.sort( array ); + float[] set = _set; + byte[] states = _states; + + _autoCompactTemporaryDisable = true; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + _autoCompactTemporaryDisable = false; + + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Float ) { + float c = ( ( Float ) element ).floatValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TFloatCollection collection ) { + boolean changed = false; + TFloatIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + float element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( float[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + float[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + set[i] = no_entry_value; + states[i] = FREE; + } + } + + + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + float oldSet[] = _set; + byte oldStates[] = _states; + + _set = new float[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + float o = oldSet[i]; + insertKey(o); + } + } + } + + + /** {@inheritDoc} */ + public boolean equals( Object other ) { + if ( ! ( other instanceof TFloatSet ) ) { + return false; + } + TFloatSet that = ( TFloatSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + public String toString() { + StringBuilder buffy = new StringBuilder( _size * 2 + 2 ); + buffy.append("{"); + for ( int i = _states.length, j = 1; i-- > 0; ) { + if ( _states[i] == FULL ) { + buffy.append( _set[i] ); + if ( j++ < _size ) { + buffy.append( "," ); + } + } + } + buffy.append("}"); + return buffy.toString(); + } + + + class TFloatHashIterator extends THashPrimitiveIterator implements TFloatIterator { + + /** the collection on which the iterator operates */ + private final TFloatHash _hash; + + /** {@inheritDoc} */ + public TFloatHashIterator( TFloatHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public float next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 1 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // LOAD FACTOR -- Added version 1 + out.writeFloat( _loadFactor ); + + // NO ENTRY VALUE -- Added version 1 + out.writeFloat( no_entry_value ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeFloat( _set[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + int version = in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + + if ( version >= 1 ) { + // LOAD FACTOR + _loadFactor = in.readFloat(); + + // NO ENTRY VALUE + no_entry_value = in.readFloat(); + //noinspection RedundantCast + if ( no_entry_value != ( float ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + // ENTRIES + setUp( size ); + while ( size-- > 0 ) { + float val = in.readFloat(); + add( val ); + } + } +} // TIntHashSet diff --git a/src/gnu/trove/set/hash/THashSet.java b/src/gnu/trove/set/hash/THashSet.java new file mode 100644 index 0000000..4f30c19 --- /dev/null +++ b/src/gnu/trove/set/hash/THashSet.java @@ -0,0 +1,410 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.impl.hash.TObjectHash; +import gnu.trove.impl.HashFunctions; +import gnu.trove.procedure.TObjectProcedure; +import gnu.trove.procedure.array.ToObjectArrayProceedure; +import gnu.trove.iterator.hash.TObjectHashIterator; + +import java.io.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.Arrays; +import java.lang.reflect.Array; + + +/** + * An implementation of the Set interface that uses an + * open-addressed hash table to store its contents. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + * @version $Id: THashSet.java,v 1.1.2.8 2010/03/02 04:09:50 robeden Exp $ + */ + +public class THashSet extends TObjectHash + implements Set, Iterable, Externalizable { + + static final long serialVersionUID = 1L; + + + /** + * Creates a new THashSet instance with the default + * capacity and load factor. + */ + public THashSet() { + super(); + } + + + /** + * Creates a new THashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public THashSet(int initialCapacity) { + super(initialCapacity); + } + + + /** + * Creates a new THashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public THashSet(int initialCapacity, float loadFactor) { + super(initialCapacity, loadFactor); + } + + + /** + * Creates a new THashSet instance containing the + * elements of collection. + * + * @param collection a Collection value + */ + public THashSet(Collection collection) { + this(collection.size()); + addAll(collection); + } + + + /** + * Inserts a value into the set. + * + * @param obj an Object value + * @return true if the set was modified by the add operation + */ + public boolean add(E obj) { + int index = insertKey(obj); + + if (index < 0) { + return false; // already present in set, nothing to add + } + + postInsertHook(consumeFreeSlot); + return true; // yes, we added something + } + + + @SuppressWarnings({}) + public boolean equals(Object other) { + if (!(other instanceof Set)) { + return false; + } + Set that = (Set) other; + if (that.size() != this.size()) { + return false; + } + return containsAll(that); + } + + + public int hashCode() { + HashProcedure p = new HashProcedure(); + forEach(p); + return p.getHashCode(); + } + + + private final class HashProcedure implements TObjectProcedure { + private int h = 0; + + public int getHashCode() { + return h; + } + + public final boolean execute(E key) { + h += HashFunctions.hash(key); + return true; + } + } + + + /** + * Expands the set to accommodate new values. + * + * @param newCapacity an int value + */ + @SuppressWarnings({"unchecked"}) + protected void rehash(int newCapacity) { + int oldCapacity = _set.length; + + int oldSize = size(); + Object oldSet[] = _set; + + _set = new Object[newCapacity]; + Arrays.fill(_set, FREE); + + for (int i = oldCapacity; i-- > 0;) { + E o = (E) oldSet[i]; + if (o != FREE && o != REMOVED) { + int index = insertKey(o); + if (index < 0) { // everyone pays for this because some people can't RTFM + throwObjectContractViolation(_set[(-index - 1)], o, size(), oldSize, oldSet); + } + } + } + // Last check: size before and after should be the same + reportPotentialConcurrentMod(size(), oldSize); + } + + /** + * Returns a new array containing the objects in the set. + * + * @return an Object[] value + */ + @SuppressWarnings({}) + public Object[] toArray() { + Object[] result = new Object[size()]; + forEach(new ToObjectArrayProceedure(result)); + return result; + } + + + /** + * Returns a typed array of the objects in the set. + * + * @param a an Object[] value + * @return an Object[] value + */ + @SuppressWarnings({"unchecked"}) + public T[] toArray(T[] a) { + int size = size(); + if (a.length < size) { + a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); + } + + forEach(new ToObjectArrayProceedure(a)); + + // If this collection fits in the specified array with room to + // spare (i.e., the array has more elements than this + // collection), the element in the array immediately following + // the end of the collection is set to null. This is useful in + // determining the length of this collection only if the + // caller knows that this collection does not contain any null + // elements.) + + if (a.length > size) { + a[size] = null; + } + + return a; + } + + + /** + * Empties the set. + */ + public void clear() { + super.clear(); + + Arrays.fill(_set, 0, _set.length, FREE); + } + + + /** + * Removes obj from the set. + * + * @param obj an Object value + * @return true if the set was modified by the remove operation. + */ + @SuppressWarnings({}) + public boolean remove(Object obj) { + int index = index(obj); + if (index >= 0) { + removeAt(index); + return true; + } + return false; + } + + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an Iterator value + */ + @SuppressWarnings({}) + public TObjectHashIterator iterator() { + return new TObjectHashIterator(this); + } + + + /** + * Tests the set to determine if all of the elements in + * collection are present. + * + * @param collection a Collection value + * @return true if all elements were present in the set. + */ + public boolean containsAll(Collection collection) { + for (Iterator i = collection.iterator(); i.hasNext();) { + if (!contains(i.next())) { + return false; + } + } + return true; + } + + + /** + * Adds all of the elements in collection to the set. + * + * @param collection a Collection value + * @return true if the set was modified by the add all operation. + */ + public boolean addAll(Collection collection) { + boolean changed = false; + int size = collection.size(); + + ensureCapacity(size); + Iterator it = collection.iterator(); + while (size-- > 0) { + if (add(it.next())) { + changed = true; + } + } + return changed; + } + + + /** + * Removes all of the elements in collection from the set. + * + * @param collection a Collection value + * @return true if the set was modified by the remove all operation. + */ + public boolean removeAll(Collection collection) { + boolean changed = false; + int size = collection.size(); + Iterator it; + + it = collection.iterator(); + while (size-- > 0) { + if (remove(it.next())) { + changed = true; + } + } + return changed; + } + + + /** + * Removes any values in the set which are not contained in + * collection. + * + * @param collection a Collection value + * @return true if the set was modified by the retain all operation + */ + @SuppressWarnings({}) + public boolean retainAll(Collection collection) { + boolean changed = false; + int size = size(); + Iterator it = iterator(); + while (size-- > 0) { + if (!collection.contains(it.next())) { + it.remove(); + changed = true; + } + } + return changed; + } + + + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + forEach(new TObjectProcedure() { + private boolean first = true; + + + public boolean execute(Object value) { + if (first) { + first = false; + } else { + buf.append(", "); + } + + buf.append(value); + return true; + } + }); + buf.append("}"); + return buf.toString(); + } + + + public void writeExternal(ObjectOutput out) throws IOException { + // VERSION + out.writeByte(1); + + // NOTE: Super was not written in version 0 + super.writeExternal(out); + + // NUMBER OF ENTRIES + out.writeInt(_size); + + // ENTRIES + writeEntries(out); + } + + protected void writeEntries(ObjectOutput out) throws IOException { + for (int i = _set.length; i-- > 0;) { + if (_set[i] != REMOVED && _set[i] != FREE) { + out.writeObject(_set[i]); + } + } + } + + @SuppressWarnings({"unchecked"}) + public void readExternal(ObjectInput in) + throws IOException, ClassNotFoundException { + + // VERSION + byte version = in.readByte(); + + // NOTE: super was not written in version 0 + if (version != 0) { + super.readExternal(in); + } + + // NUMBER OF ENTRIES + int size = in.readInt(); + setUp(size); + + // ENTRIES + while (size-- > 0) { + E val = (E) in.readObject(); + add(val); + } + + } +} // THashSet diff --git a/src/gnu/trove/set/hash/TIntHashSet.java b/src/gnu/trove/set/hash/TIntHashSet.java new file mode 100644 index 0000000..1d0be3b --- /dev/null +++ b/src/gnu/trove/set/hash/TIntHashSet.java @@ -0,0 +1,555 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.set.TIntSet; +import gnu.trove.iterator.TIntIterator; +import gnu.trove.impl.*; +import gnu.trove.impl.hash.*; +import gnu.trove.TIntCollection; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Externalizable; +import java.util.Arrays; +import java.util.Collection; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed set implementation for int primitives. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ + +public class TIntHashSet extends TIntHash implements TIntSet, Externalizable { + static final long serialVersionUID = 1L; + + + /** + * Creates a new TIntHashSet instance with the default + * capacity and load factor. + */ + public TIntHashSet() { + super(); + } + + + /** + * Creates a new TIntHashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TIntHashSet( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param load_factor used to calculate the threshold over which + * rehashing takes place. + */ + public TIntHashSet( int initialCapacity, float load_factor ) { + super( initialCapacity, load_factor ); + } + + + /** + * Creates a new TIntHashSet instance with a prime + * capacity equal to or greater than initial_capacity and + * with the specified load factor. + * + * @param initial_capacity an int value + * @param load_factor a float value + * @param no_entry_value a int value that represents null. + */ + public TIntHashSet( int initial_capacity, float load_factor, + int no_entry_value ) { + super( initial_capacity, load_factor, no_entry_value ); + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TIntHashSet instance that is a copy + * of the existing Collection. + * + * @param collection a Collection that will be duplicated. + */ + public TIntHashSet( Collection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + addAll( collection ); + } + + + /** + * Creates a new TIntHashSet instance that is a copy + * of the existing set. + * + * @param collection a TIntSet that will be duplicated. + */ + public TIntHashSet( TIntCollection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + if ( collection instanceof TIntHashSet ) { + TIntHashSet hashset = ( TIntHashSet ) collection; + this._loadFactor = hashset._loadFactor; + this.no_entry_value = hashset.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( int ) 0 ) { + Arrays.fill( _set, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + addAll( collection ); + } + + + /** + * Creates a new TIntHashSet instance containing the + * elements of array. + * + * @param array an array of int primitives + */ + public TIntHashSet( int[] array ) { + this( Math.max( array.length, DEFAULT_CAPACITY ) ); + addAll( array ); + } + + + /** {@inheritDoc} */ + public TIntIterator iterator() { + return new TIntHashIterator( this ); + } + + + /** {@inheritDoc} */ + public int[] toArray() { + int[] result = new int[ size() ]; + if ( result.length == 0 ) { + return result; // nothing to copy + } + int[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + result[j++] = set[i]; + } + } + return result; + } + + + /** {@inheritDoc} */ + public int[] toArray( int[] dest ) { + if ( dest.length == 0 ) { + return dest; // nothing to copy + } + int[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = set[i]; + } + } + + if ( dest.length > _size ) { + dest[_size] = no_entry_value; + } + return dest; + } + + + /** {@inheritDoc} */ + public boolean add( int val ) { + int index = insertKey(val); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + + return true; // yes, we added something + } + + + /** {@inheritDoc} */ + public boolean remove( int val ) { + int index = index(val); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TIntCollection collection ) { + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( int[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Integer element : collection ) { + int e = element.intValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TIntCollection collection ) { + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( add( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TIntCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TIntIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( int[] array ) { + boolean changed = false; + Arrays.sort( array ); + int[] set = _set; + byte[] states = _states; + + _autoCompactTemporaryDisable = true; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + _autoCompactTemporaryDisable = false; + + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Integer ) { + int c = ( ( Integer ) element ).intValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TIntCollection collection ) { + boolean changed = false; + TIntIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + int element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( int[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + int[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + set[i] = no_entry_value; + states[i] = FREE; + } + } + + + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + int oldSet[] = _set; + byte oldStates[] = _states; + + _set = new int[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + int o = oldSet[i]; + insertKey(o); + } + } + } + + + /** {@inheritDoc} */ + public boolean equals( Object other ) { + if ( ! ( other instanceof TIntSet ) ) { + return false; + } + TIntSet that = ( TIntSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + public String toString() { + StringBuilder buffy = new StringBuilder( _size * 2 + 2 ); + buffy.append("{"); + for ( int i = _states.length, j = 1; i-- > 0; ) { + if ( _states[i] == FULL ) { + buffy.append( _set[i] ); + if ( j++ < _size ) { + buffy.append( "," ); + } + } + } + buffy.append("}"); + return buffy.toString(); + } + + + class TIntHashIterator extends THashPrimitiveIterator implements TIntIterator { + + /** the collection on which the iterator operates */ + private final TIntHash _hash; + + /** {@inheritDoc} */ + public TIntHashIterator( TIntHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public int next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 1 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // LOAD FACTOR -- Added version 1 + out.writeFloat( _loadFactor ); + + // NO ENTRY VALUE -- Added version 1 + out.writeInt( no_entry_value ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeInt( _set[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + int version = in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + + if ( version >= 1 ) { + // LOAD FACTOR + _loadFactor = in.readFloat(); + + // NO ENTRY VALUE + no_entry_value = in.readInt(); + //noinspection RedundantCast + if ( no_entry_value != ( int ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + // ENTRIES + setUp( size ); + while ( size-- > 0 ) { + int val = in.readInt(); + add( val ); + } + } +} // TIntHashSet diff --git a/src/gnu/trove/set/hash/TLinkedHashSet.java b/src/gnu/trove/set/hash/TLinkedHashSet.java new file mode 100644 index 0000000..50b455d --- /dev/null +++ b/src/gnu/trove/set/hash/TLinkedHashSet.java @@ -0,0 +1,321 @@ +package gnu.trove.set.hash; + +import gnu.trove.iterator.TIntIterator; +import gnu.trove.iterator.hash.TObjectHashIterator; +import gnu.trove.list.TIntList; +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.list.linked.TIntLinkedList; +import gnu.trove.procedure.TIntProcedure; +import gnu.trove.procedure.TObjectProcedure; + +import java.io.IOException; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; + +/** + * Created by IntelliJ IDEA. + * User: Johan + * Date: 15/03/11 + * Time: 18:15 + * To change this template use File | Settings | File Templates. + */ +public class TLinkedHashSet extends THashSet { + TIntList order; + + /** + * Creates a new THashSet instance with the default + * capacity and load factor. + */ + public TLinkedHashSet() { + } + + /** + * Creates a new THashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLinkedHashSet(int initialCapacity) { + super(initialCapacity); + } + + /** + * Creates a new THashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the specified load factor. + * + * @param initialCapacity an int value + * @param loadFactor a float value + */ + public TLinkedHashSet(int initialCapacity, float loadFactor) { + super(initialCapacity, loadFactor); + } + + /** + * Creates a new THashSet instance containing the + * elements of collection. + * + * @param es a Collection value + */ + public TLinkedHashSet(Collection es) { + super(es); + } + + /** + * initializes the Object set of this hash table. + * + * @param initialCapacity an int value + * @return an int value + */ + @Override + public int setUp(int initialCapacity) { + order = new TIntArrayList(initialCapacity) { + /** + * Grow the internal array as needed to accommodate the specified number of elements. + * The size of the array bytes on each resize unless capacity requires more than twice + * the current capacity. + */ + @Override + public void ensureCapacity(int capacity) { + if (capacity > _data.length) { + int newCap = Math.max(_set.length, capacity); + int[] tmp = new int[newCap]; + System.arraycopy(_data, 0, tmp, 0, _data.length); + _data = tmp; + } + } + }; + return super.setUp(initialCapacity); //To change body of overridden methods use File | Settings | File Templates. + } + + + /** + * Empties the set. + */ + @Override + public void clear() { + super.clear(); + order.clear(); + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder("{"); + boolean first = true; + + for (Iterator it = iterator(); it.hasNext();) { + if (first) { + first = false; + } else { + buf.append(", "); + } + + buf.append(it.next()); + } + + buf.append("}"); + return buf.toString(); + } + + /** + * Inserts a value into the set. + * + * @param obj an Object value + * @return true if the set was modified by the add operation + */ + @Override + public boolean add(E obj) { + int index = insertKey(obj); + + if (index < 0) { + return false; // already present in set, nothing to add + } + + if (!order.add(index)) + throw new IllegalStateException("Order not changed after insert"); + + postInsertHook(consumeFreeSlot); + return true; // yes, we added something + } + + @Override + protected void removeAt(int index) { + // Remove from order first since super.removeAt can trigger compaction + // making the index invalid afterwards + order.remove(index); + super.removeAt(index); + } + + + /** + * Expands the set to accommodate new values. + * + * @param newCapacity an int value + */ + @SuppressWarnings("unchecked") + @Override + protected void rehash(int newCapacity) { + TIntLinkedList oldOrder = new TIntLinkedList(order); + int oldSize = size(); + + Object oldSet[] = _set; + + order.clear(); + _set = new Object[newCapacity]; + Arrays.fill(_set, FREE); + + for (TIntIterator iterator = oldOrder.iterator(); iterator.hasNext();) { + int i = iterator.next(); + E o = (E) oldSet[i]; + if (o == FREE || o == REMOVED) { + throw new IllegalStateException("Iterating over empty location while rehashing"); + } + + if (o != FREE && o != REMOVED) { + int index = insertKey(o); + if (index < 0) { // everyone pays for this because some people can't RTFM + throwObjectContractViolation(_set[(-index - 1)], o, size(), oldSize, oldSet); + } + + if (!order.add(index)) + throw new IllegalStateException("Order not changed after insert"); + } + } + + } + + class WriteProcedure implements TIntProcedure { + final ObjectOutput output; + IOException ioException; + + WriteProcedure(ObjectOutput output) { + this.output = output; + } + + public IOException getIoException() { + return ioException; + } + + public boolean execute(int value) { + try { + output.writeObject(_set[value]); + } catch (IOException e) { + ioException = e; + return false; + } + return true; + } + + } + + @Override + protected void writeEntries(ObjectOutput out) throws IOException { + // ENTRIES + WriteProcedure writeProcedure = new WriteProcedure(out); + if (!order.forEach(writeProcedure)) + throw writeProcedure.getIoException(); + } + + /** + * Creates an iterator over the values of the set. The iterator + * supports element deletion. + * + * @return an Iterator value + */ + @Override + public TObjectHashIterator iterator() { + return new TObjectHashIterator(this) { + TIntIterator localIterator = order.iterator(); + int lastIndex; + + /** + * Moves the iterator to the next Object and returns it. + * + * @return an Object value + * @throws java.util.ConcurrentModificationException + * if the structure + * was changed using a method that isn't on this iterator. + * @throws java.util.NoSuchElementException + * if this is called on an + * exhausted iterator. + */ + @Override + public E next() { + lastIndex = localIterator.next(); + return objectAtIndex(lastIndex); + } + + /** + * Returns true if the iterator can be advanced past its current + * location. + * + * @return a boolean value + */ + @Override + public boolean hasNext() { + return localIterator.hasNext(); //To change body of overridden methods use File | Settings | File Templates. + } + + /** + * Removes the last entry returned by the iterator. + * Invoking this method more than once for a single entry + * will leave the underlying data structure in a confused + * state. + */ + @Override + public void remove() { + // Remove for iterator first + localIterator.remove(); + // the removal within removeAt() will not change the collection + // but the localIterator will remain valid + try { + _hash.tempDisableAutoCompaction(); + TLinkedHashSet.this.removeAt(lastIndex); + } finally { + _hash.reenableAutoCompaction(false); + } + } + }; //To change body of overridden methods use File | Settings | File Templates. + } + + class ForEachProcedure implements TIntProcedure { + boolean changed = false; + final Object[] set; + final TObjectProcedure procedure; + + public ForEachProcedure(Object[] set, TObjectProcedure procedure) { + this.set = set; + this.procedure = procedure; + } + + /** + * Executes this procedure. A false return value indicates that + * the application executing this procedure should not invoke this + * procedure again. + * + * @param value a value of type int + * @return true if additional invocations of the procedure are + * allowed. + */ + @SuppressWarnings("unchecked") + public boolean execute(int value) { + return procedure.execute((E) set[value]); + } + } + + /** + * Executes procedure for each element in the set. + * + * @param procedure a TObjectProcedure value + * @return false if the loop over the set terminated because + * the procedure returned false for some value. + */ + @Override + public boolean forEach(TObjectProcedure procedure) { + ForEachProcedure forEachProcedure = new ForEachProcedure(_set, procedure); + return order.forEach(forEachProcedure); + } +} diff --git a/src/gnu/trove/set/hash/TLongHashSet.java b/src/gnu/trove/set/hash/TLongHashSet.java new file mode 100644 index 0000000..b6d8018 --- /dev/null +++ b/src/gnu/trove/set/hash/TLongHashSet.java @@ -0,0 +1,555 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.set.TLongSet; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.impl.*; +import gnu.trove.impl.hash.*; +import gnu.trove.TLongCollection; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Externalizable; +import java.util.Arrays; +import java.util.Collection; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed set implementation for long primitives. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ + +public class TLongHashSet extends TLongHash implements TLongSet, Externalizable { + static final long serialVersionUID = 1L; + + + /** + * Creates a new TLongHashSet instance with the default + * capacity and load factor. + */ + public TLongHashSet() { + super(); + } + + + /** + * Creates a new TLongHashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TLongHashSet( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param load_factor used to calculate the threshold over which + * rehashing takes place. + */ + public TLongHashSet( int initialCapacity, float load_factor ) { + super( initialCapacity, load_factor ); + } + + + /** + * Creates a new TLongHashSet instance with a prime + * capacity equal to or greater than initial_capacity and + * with the specified load factor. + * + * @param initial_capacity an int value + * @param load_factor a float value + * @param no_entry_value a long value that represents null. + */ + public TLongHashSet( int initial_capacity, float load_factor, + long no_entry_value ) { + super( initial_capacity, load_factor, no_entry_value ); + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TLongHashSet instance that is a copy + * of the existing Collection. + * + * @param collection a Collection that will be duplicated. + */ + public TLongHashSet( Collection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + addAll( collection ); + } + + + /** + * Creates a new TLongHashSet instance that is a copy + * of the existing set. + * + * @param collection a TLongSet that will be duplicated. + */ + public TLongHashSet( TLongCollection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + if ( collection instanceof TLongHashSet ) { + TLongHashSet hashset = ( TLongHashSet ) collection; + this._loadFactor = hashset._loadFactor; + this.no_entry_value = hashset.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( long ) 0 ) { + Arrays.fill( _set, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + addAll( collection ); + } + + + /** + * Creates a new TLongHashSet instance containing the + * elements of array. + * + * @param array an array of long primitives + */ + public TLongHashSet( long[] array ) { + this( Math.max( array.length, DEFAULT_CAPACITY ) ); + addAll( array ); + } + + + /** {@inheritDoc} */ + public TLongIterator iterator() { + return new TLongHashIterator( this ); + } + + + /** {@inheritDoc} */ + public long[] toArray() { + long[] result = new long[ size() ]; + if ( result.length == 0 ) { + return result; // nothing to copy + } + long[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + result[j++] = set[i]; + } + } + return result; + } + + + /** {@inheritDoc} */ + public long[] toArray( long[] dest ) { + if ( dest.length == 0 ) { + return dest; // nothing to copy + } + long[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = set[i]; + } + } + + if ( dest.length > _size ) { + dest[_size] = no_entry_value; + } + return dest; + } + + + /** {@inheritDoc} */ + public boolean add( long val ) { + int index = insertKey(val); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + + return true; // yes, we added something + } + + + /** {@inheritDoc} */ + public boolean remove( long val ) { + int index = index(val); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TLongCollection collection ) { + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( long[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Long element : collection ) { + long e = element.longValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TLongCollection collection ) { + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( add( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TLongCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TLongIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( long[] array ) { + boolean changed = false; + Arrays.sort( array ); + long[] set = _set; + byte[] states = _states; + + _autoCompactTemporaryDisable = true; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + _autoCompactTemporaryDisable = false; + + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Long ) { + long c = ( ( Long ) element ).longValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TLongCollection collection ) { + boolean changed = false; + TLongIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + long element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( long[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + long[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + set[i] = no_entry_value; + states[i] = FREE; + } + } + + + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + long oldSet[] = _set; + byte oldStates[] = _states; + + _set = new long[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + long o = oldSet[i]; + insertKey(o); + } + } + } + + + /** {@inheritDoc} */ + public boolean equals( Object other ) { + if ( ! ( other instanceof TLongSet ) ) { + return false; + } + TLongSet that = ( TLongSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + public String toString() { + StringBuilder buffy = new StringBuilder( _size * 2 + 2 ); + buffy.append("{"); + for ( int i = _states.length, j = 1; i-- > 0; ) { + if ( _states[i] == FULL ) { + buffy.append( _set[i] ); + if ( j++ < _size ) { + buffy.append( "," ); + } + } + } + buffy.append("}"); + return buffy.toString(); + } + + + class TLongHashIterator extends THashPrimitiveIterator implements TLongIterator { + + /** the collection on which the iterator operates */ + private final TLongHash _hash; + + /** {@inheritDoc} */ + public TLongHashIterator( TLongHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public long next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 1 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // LOAD FACTOR -- Added version 1 + out.writeFloat( _loadFactor ); + + // NO ENTRY VALUE -- Added version 1 + out.writeLong( no_entry_value ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeLong( _set[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + int version = in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + + if ( version >= 1 ) { + // LOAD FACTOR + _loadFactor = in.readFloat(); + + // NO ENTRY VALUE + no_entry_value = in.readLong(); + //noinspection RedundantCast + if ( no_entry_value != ( long ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + // ENTRIES + setUp( size ); + while ( size-- > 0 ) { + long val = in.readLong(); + add( val ); + } + } +} // TIntHashSet diff --git a/src/gnu/trove/set/hash/TShortHashSet.java b/src/gnu/trove/set/hash/TShortHashSet.java new file mode 100644 index 0000000..5b6f7d1 --- /dev/null +++ b/src/gnu/trove/set/hash/TShortHashSet.java @@ -0,0 +1,555 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.set.hash; + +import gnu.trove.set.TShortSet; +import gnu.trove.iterator.TShortIterator; +import gnu.trove.impl.*; +import gnu.trove.impl.hash.*; +import gnu.trove.TShortCollection; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Externalizable; +import java.util.Arrays; +import java.util.Collection; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * An open addressed set implementation for short primitives. + * + * @author Eric D. Friedman + * @author Rob Eden + * @author Jeff Randall + */ + +public class TShortHashSet extends TShortHash implements TShortSet, Externalizable { + static final long serialVersionUID = 1L; + + + /** + * Creates a new TShortHashSet instance with the default + * capacity and load factor. + */ + public TShortHashSet() { + super(); + } + + + /** + * Creates a new TShortHashSet instance with a prime + * capacity equal to or greater than initialCapacity and + * with the default load factor. + * + * @param initialCapacity an int value + */ + public TShortHashSet( int initialCapacity ) { + super( initialCapacity ); + } + + + /** + * Creates a new TIntHash instance with a prime + * value at or near the specified capacity and load factor. + * + * @param initialCapacity used to find a prime capacity for the table. + * @param load_factor used to calculate the threshold over which + * rehashing takes place. + */ + public TShortHashSet( int initialCapacity, float load_factor ) { + super( initialCapacity, load_factor ); + } + + + /** + * Creates a new TShortHashSet instance with a prime + * capacity equal to or greater than initial_capacity and + * with the specified load factor. + * + * @param initial_capacity an int value + * @param load_factor a float value + * @param no_entry_value a short value that represents null. + */ + public TShortHashSet( int initial_capacity, float load_factor, + short no_entry_value ) { + super( initial_capacity, load_factor, no_entry_value ); + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + + /** + * Creates a new TShortHashSet instance that is a copy + * of the existing Collection. + * + * @param collection a Collection that will be duplicated. + */ + public TShortHashSet( Collection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + addAll( collection ); + } + + + /** + * Creates a new TShortHashSet instance that is a copy + * of the existing set. + * + * @param collection a TShortSet that will be duplicated. + */ + public TShortHashSet( TShortCollection collection ) { + this( Math.max( collection.size(), DEFAULT_CAPACITY ) ); + if ( collection instanceof TShortHashSet ) { + TShortHashSet hashset = ( TShortHashSet ) collection; + this._loadFactor = hashset._loadFactor; + this.no_entry_value = hashset.no_entry_value; + //noinspection RedundantCast + if ( this.no_entry_value != ( short ) 0 ) { + Arrays.fill( _set, this.no_entry_value ); + } + setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) ); + } + addAll( collection ); + } + + + /** + * Creates a new TShortHashSet instance containing the + * elements of array. + * + * @param array an array of short primitives + */ + public TShortHashSet( short[] array ) { + this( Math.max( array.length, DEFAULT_CAPACITY ) ); + addAll( array ); + } + + + /** {@inheritDoc} */ + public TShortIterator iterator() { + return new TShortHashIterator( this ); + } + + + /** {@inheritDoc} */ + public short[] toArray() { + short[] result = new short[ size() ]; + if ( result.length == 0 ) { + return result; // nothing to copy + } + short[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + result[j++] = set[i]; + } + } + return result; + } + + + /** {@inheritDoc} */ + public short[] toArray( short[] dest ) { + if ( dest.length == 0 ) { + return dest; // nothing to copy + } + short[] set = _set; + byte[] states = _states; + + for ( int i = states.length, j = 0; i-- > 0; ) { + if ( states[i] == FULL ) { + dest[j++] = set[i]; + } + } + + if ( dest.length > _size ) { + dest[_size] = no_entry_value; + } + return dest; + } + + + /** {@inheritDoc} */ + public boolean add( short val ) { + int index = insertKey(val); + + if ( index < 0 ) { + return false; // already present in set, nothing to add + } + + postInsertHook( consumeFreeSlot ); + + return true; // yes, we added something + } + + + /** {@inheritDoc} */ + public boolean remove( short val ) { + int index = index(val); + if ( index >= 0 ) { + removeAt( index ); + return true; + } + return false; + } + + + /** {@inheritDoc} */ + public boolean containsAll( Collection collection ) { + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( ! contains( c ) ) { + return false; + } + } else { + return false; + } + + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( TShortCollection collection ) { + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( ! contains( element ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean containsAll( short[] array ) { + for ( int i = array.length; i-- > 0; ) { + if ( ! contains( array[i] ) ) { + return false; + } + } + return true; + } + + + /** {@inheritDoc} */ + public boolean addAll( Collection collection ) { + boolean changed = false; + for ( Short element : collection ) { + short e = element.shortValue(); + if ( add( e ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( TShortCollection collection ) { + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( add( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean addAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( add( array[i] ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + @SuppressWarnings({}) + public boolean retainAll( Collection collection ) { + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( Short.valueOf ( iter.next() ) ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( TShortCollection collection ) { + if ( this == collection ) { + return false; + } + boolean modified = false; + TShortIterator iter = iterator(); + while ( iter.hasNext() ) { + if ( ! collection.contains( iter.next() ) ) { + iter.remove(); + modified = true; + } + } + return modified; + } + + + /** {@inheritDoc} */ + public boolean retainAll( short[] array ) { + boolean changed = false; + Arrays.sort( array ); + short[] set = _set; + byte[] states = _states; + + _autoCompactTemporaryDisable = true; + for ( int i = set.length; i-- > 0; ) { + if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) { + removeAt( i ); + changed = true; + } + } + _autoCompactTemporaryDisable = false; + + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( Collection collection ) { + boolean changed = false; + for ( Object element : collection ) { + if ( element instanceof Short ) { + short c = ( ( Short ) element ).shortValue(); + if ( remove( c ) ) { + changed = true; + } + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( TShortCollection collection ) { + boolean changed = false; + TShortIterator iter = collection.iterator(); + while ( iter.hasNext() ) { + short element = iter.next(); + if ( remove( element ) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public boolean removeAll( short[] array ) { + boolean changed = false; + for ( int i = array.length; i-- > 0; ) { + if ( remove(array[i]) ) { + changed = true; + } + } + return changed; + } + + + /** {@inheritDoc} */ + public void clear() { + super.clear(); + short[] set = _set; + byte[] states = _states; + + for ( int i = set.length; i-- > 0; ) { + set[i] = no_entry_value; + states[i] = FREE; + } + } + + + /** {@inheritDoc} */ + protected void rehash( int newCapacity ) { + int oldCapacity = _set.length; + + short oldSet[] = _set; + byte oldStates[] = _states; + + _set = new short[newCapacity]; + _states = new byte[newCapacity]; + + for ( int i = oldCapacity; i-- > 0; ) { + if( oldStates[i] == FULL ) { + short o = oldSet[i]; + insertKey(o); + } + } + } + + + /** {@inheritDoc} */ + public boolean equals( Object other ) { + if ( ! ( other instanceof TShortSet ) ) { + return false; + } + TShortSet that = ( TShortSet ) other; + if ( that.size() != this.size() ) { + return false; + } + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + if ( ! that.contains( _set[i] ) ) { + return false; + } + } + } + return true; + } + + + /** {@inheritDoc} */ + public int hashCode() { + int hashcode = 0; + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + hashcode += HashFunctions.hash( _set[i] ); + } + } + return hashcode; + } + + + /** {@inheritDoc} */ + public String toString() { + StringBuilder buffy = new StringBuilder( _size * 2 + 2 ); + buffy.append("{"); + for ( int i = _states.length, j = 1; i-- > 0; ) { + if ( _states[i] == FULL ) { + buffy.append( _set[i] ); + if ( j++ < _size ) { + buffy.append( "," ); + } + } + } + buffy.append("}"); + return buffy.toString(); + } + + + class TShortHashIterator extends THashPrimitiveIterator implements TShortIterator { + + /** the collection on which the iterator operates */ + private final TShortHash _hash; + + /** {@inheritDoc} */ + public TShortHashIterator( TShortHash hash ) { + super( hash ); + this._hash = hash; + } + + /** {@inheritDoc} */ + public short next() { + moveToNextIndex(); + return _hash._set[_index]; + } + } + + + /** {@inheritDoc} */ + public void writeExternal( ObjectOutput out ) throws IOException { + + // VERSION + out.writeByte( 1 ); + + // SUPER + super.writeExternal( out ); + + // NUMBER OF ENTRIES + out.writeInt( _size ); + + // LOAD FACTOR -- Added version 1 + out.writeFloat( _loadFactor ); + + // NO ENTRY VALUE -- Added version 1 + out.writeShort( no_entry_value ); + + // ENTRIES + for ( int i = _states.length; i-- > 0; ) { + if ( _states[i] == FULL ) { + out.writeShort( _set[i] ); + } + } + } + + + /** {@inheritDoc} */ + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + int version = in.readByte(); + + // SUPER + super.readExternal( in ); + + // NUMBER OF ENTRIES + int size = in.readInt(); + + if ( version >= 1 ) { + // LOAD FACTOR + _loadFactor = in.readFloat(); + + // NO ENTRY VALUE + no_entry_value = in.readShort(); + //noinspection RedundantCast + if ( no_entry_value != ( short ) 0 ) { + Arrays.fill( _set, no_entry_value ); + } + } + + // ENTRIES + setUp( size ); + while ( size-- > 0 ) { + short val = in.readShort(); + add( val ); + } + } +} // TIntHashSet diff --git a/src/gnu/trove/stack/TByteStack.java b/src/gnu/trove/stack/TByteStack.java new file mode 100644 index 0000000..8b00e9b --- /dev/null +++ b/src/gnu/trove/stack/TByteStack.java @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + + + +/** + * A stack of byte primitives. + */ +public interface TByteStack { + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue(); + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an byte value + */ + public void push( byte val ); + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an byte value + */ + public byte pop(); + + + /** + * Returns the value at the top of the stack. + * + * @return an byte value + */ + public byte peek(); + + + /** + * Returns the current depth of the stack. + */ + public int size(); + + + /** + * Clears the stack. + */ + public void clear(); + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. + * + * @return an byte[] value + */ + public byte[] toArray(); + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. + * + * @param dest the array to copy into. + */ + public void toArray( byte[] dest ); +} diff --git a/src/gnu/trove/stack/TCharStack.java b/src/gnu/trove/stack/TCharStack.java new file mode 100644 index 0000000..08dd9b8 --- /dev/null +++ b/src/gnu/trove/stack/TCharStack.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack; + +/** + * A stack of char primitives. + */ +public interface TCharStack { + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue(); + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an char value + */ + public void push( char val ); + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an char value + */ + public char pop(); + + + /** + * Returns the value at the top of the stack. + * + * @return an char value + */ + public char peek(); + + + /** + * Returns the current depth of the stack. + */ + public int size(); + + + /** + * Clears the stack. + */ + public void clear(); + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. + * + * @return an char[] value + */ + public char[] toArray(); + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. + * + * @param dest the array to copy into. + */ + public void toArray( char[] dest ); +} diff --git a/src/gnu/trove/stack/TDoubleStack.java b/src/gnu/trove/stack/TDoubleStack.java new file mode 100644 index 0000000..68390d9 --- /dev/null +++ b/src/gnu/trove/stack/TDoubleStack.java @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack; + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + + + +/** + * A stack of double primitives. + */ +public interface TDoubleStack { + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue(); + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an double value + */ + public void push( double val ); + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an double value + */ + public double pop(); + + + /** + * Returns the value at the top of the stack. + * + * @return an double value + */ + public double peek(); + + + /** + * Returns the current depth of the stack. + */ + public int size(); + + + /** + * Clears the stack. + */ + public void clear(); + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. + * + * @return an double[] value + */ + public double[] toArray(); + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. + * + * @param dest the array to copy into. + */ + public void toArray( double[] dest ); +} diff --git a/src/gnu/trove/stack/TFloatStack.java b/src/gnu/trove/stack/TFloatStack.java new file mode 100644 index 0000000..4bf4d0d --- /dev/null +++ b/src/gnu/trove/stack/TFloatStack.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack; + +/** + * A stack of float primitives. + */ +public interface TFloatStack { + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue(); + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an float value + */ + public void push( float val ); + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an float value + */ + public float pop(); + + + /** + * Returns the value at the top of the stack. + * + * @return an float value + */ + public float peek(); + + + /** + * Returns the current depth of the stack. + */ + public int size(); + + + /** + * Clears the stack. + */ + public void clear(); + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. + * + * @return an float[] value + */ + public float[] toArray(); + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. + * + * @param dest the array to copy into. + */ + public void toArray( float[] dest ); +} diff --git a/src/gnu/trove/stack/TIntStack.java b/src/gnu/trove/stack/TIntStack.java new file mode 100644 index 0000000..a36e33e --- /dev/null +++ b/src/gnu/trove/stack/TIntStack.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack; + +/** + * A stack of int primitives. + */ +public interface TIntStack { + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue(); + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an int value + */ + public void push( int val ); + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an int value + */ + public int pop(); + + + /** + * Returns the value at the top of the stack. + * + * @return an int value + */ + public int peek(); + + + /** + * Returns the current depth of the stack. + */ + public int size(); + + + /** + * Clears the stack. + */ + public void clear(); + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. + * + * @return an int[] value + */ + public int[] toArray(); + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. + * + * @param dest the array to copy into. + */ + public void toArray( int[] dest ); +} diff --git a/src/gnu/trove/stack/TLongStack.java b/src/gnu/trove/stack/TLongStack.java new file mode 100644 index 0000000..2ab022c --- /dev/null +++ b/src/gnu/trove/stack/TLongStack.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack; + +/** + * A stack of long primitives. + */ +public interface TLongStack { + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue(); + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an long value + */ + public void push( long val ); + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an long value + */ + public long pop(); + + + /** + * Returns the value at the top of the stack. + * + * @return an long value + */ + public long peek(); + + + /** + * Returns the current depth of the stack. + */ + public int size(); + + + /** + * Clears the stack. + */ + public void clear(); + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. + * + * @return an long[] value + */ + public long[] toArray(); + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. + * + * @param dest the array to copy into. + */ + public void toArray( long[] dest ); +} diff --git a/src/gnu/trove/stack/TShortStack.java b/src/gnu/trove/stack/TShortStack.java new file mode 100644 index 0000000..1c73d7a --- /dev/null +++ b/src/gnu/trove/stack/TShortStack.java @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack; + +/** + * A stack of short primitives. + */ +public interface TShortStack { + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue(); + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an short value + */ + public void push( short val ); + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an short value + */ + public short pop(); + + + /** + * Returns the value at the top of the stack. + * + * @return an short value + */ + public short peek(); + + + /** + * Returns the current depth of the stack. + */ + public int size(); + + + /** + * Clears the stack. + */ + public void clear(); + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. + * + * @return an short[] value + */ + public short[] toArray(); + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. + * + * @param dest the array to copy into. + */ + public void toArray( short[] dest ); +} diff --git a/src/gnu/trove/stack/array/TByteArrayStack.java b/src/gnu/trove/stack/array/TByteArrayStack.java new file mode 100644 index 0000000..5982e2e --- /dev/null +++ b/src/gnu/trove/stack/array/TByteArrayStack.java @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack.array; + +import gnu.trove.stack.TByteStack; +import gnu.trove.list.array.TByteArrayList; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A stack of byte primitives, backed by a TByteArrayList + */ +public class TByteArrayStack implements TByteStack, Externalizable { + static final long serialVersionUID = 1L; + + /** the list used to hold the stack values. */ + protected TByteArrayList _list; + + public static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** + * Creates a new TByteArrayStack instance with the default + * capacity. + */ + public TByteArrayStack() { + this( DEFAULT_CAPACITY ); + } + + + /** + * Creates a new TByteArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + */ + public TByteArrayStack( int capacity ) { + _list = new TByteArrayList( capacity ); + } + + + /** + * Creates a new TByteArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + * @param no_entry_value value that represents null + */ + public TByteArrayStack( int capacity, byte no_entry_value ) { + _list = new TByteArrayList( capacity, no_entry_value ); + } + + + /** + * Creates a new TByteArrayStack instance that is + * a copy of the instanced passed to us. + * + * @param stack the instance to copy + */ + public TByteArrayStack( TByteStack stack ) { + if ( stack instanceof TByteArrayStack ) { + TByteArrayStack array_stack = ( TByteArrayStack ) stack; + this._list = new TByteArrayList( array_stack._list ); + } else { + throw new UnsupportedOperationException( "Only support TByteArrayStack" ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public byte getNoEntryValue() { + return _list.getNoEntryValue(); + } + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an byte value + */ + public void push( byte val ) { + _list.add( val ); + } + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an byte value + */ + public byte pop() { + return _list.removeAt( _list.size() - 1 ); + } + + + /** + * Returns the value at the top of the stack. + * + * @return an byte value + */ + public byte peek() { + return _list.get( _list.size() - 1 ); + } + + + /** + * Returns the current depth of the stack. + */ + public int size() { + return _list.size(); + } + + + /** + * Clears the stack. + */ + public void clear() { + _list.clear(); + } + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top of the stack. + * + * @return an byte[] value + */ + public byte[] toArray() { + byte[] retval = _list.toArray(); + reverse( retval, 0, size() ); + return retval; + } + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top + * of the stack. + *

+ * If the native array is smaller than the stack depth, + * the native array will be filled with the elements from the top + * of the array until it is full and exclude the remainder. + * + * @param dest the array to copy into. + */ + public void toArray( byte[] dest ) { + int size = size(); + int start = size - dest.length; + if ( start < 0 ) { + start = 0; + } + + int length = Math.min( size, dest.length ); + _list.toArray( dest, start, length ); + reverse( dest, 0, length ); + if ( dest.length > size ) { + dest[size] = _list.getNoEntryValue(); + } + } + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param dest the array of data + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + private void reverse( byte[] dest, int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( dest, i, j ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param dest the array of data + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( byte[] dest, int i, int j ) { + byte tmp = dest[ i ]; + dest[ i ] = dest[ j ]; + dest[ j ] = tmp; + } + + + /** + * Returns a String representation of the list, top to bottom. + * + * @return a String value + */ + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = _list.size() - 1; i > 0; i-- ) { + buf.append( _list.get( i ) ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _list.get( 0 ) ); + } + buf.append( "}" ); + return buf.toString(); + } + + + public boolean equals( Object o ) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TByteArrayStack that = ( TByteArrayStack ) o; + + return _list.equals( that._list ); + } + + + public int hashCode() { + return _list.hashCode(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LIST + out.writeObject( _list ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + _list = ( TByteArrayList ) in.readObject(); + } +} // TByteArrayStack diff --git a/src/gnu/trove/stack/array/TCharArrayStack.java b/src/gnu/trove/stack/array/TCharArrayStack.java new file mode 100644 index 0000000..ddab0c1 --- /dev/null +++ b/src/gnu/trove/stack/array/TCharArrayStack.java @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack.array; + +import gnu.trove.stack.TCharStack; +import gnu.trove.list.array.TCharArrayList; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A stack of char primitives, backed by a TCharArrayList + */ +public class TCharArrayStack implements TCharStack, Externalizable { + static final long serialVersionUID = 1L; + + /** the list used to hold the stack values. */ + protected TCharArrayList _list; + + public static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** + * Creates a new TCharArrayStack instance with the default + * capacity. + */ + public TCharArrayStack() { + this( DEFAULT_CAPACITY ); + } + + + /** + * Creates a new TCharArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + */ + public TCharArrayStack( int capacity ) { + _list = new TCharArrayList( capacity ); + } + + + /** + * Creates a new TCharArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + * @param no_entry_value value that represents null + */ + public TCharArrayStack( int capacity, char no_entry_value ) { + _list = new TCharArrayList( capacity, no_entry_value ); + } + + + /** + * Creates a new TCharArrayStack instance that is + * a copy of the instanced passed to us. + * + * @param stack the instance to copy + */ + public TCharArrayStack( TCharStack stack ) { + if ( stack instanceof TCharArrayStack ) { + TCharArrayStack array_stack = ( TCharArrayStack ) stack; + this._list = new TCharArrayList( array_stack._list ); + } else { + throw new UnsupportedOperationException( "Only support TCharArrayStack" ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public char getNoEntryValue() { + return _list.getNoEntryValue(); + } + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an char value + */ + public void push( char val ) { + _list.add( val ); + } + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an char value + */ + public char pop() { + return _list.removeAt( _list.size() - 1 ); + } + + + /** + * Returns the value at the top of the stack. + * + * @return an char value + */ + public char peek() { + return _list.get( _list.size() - 1 ); + } + + + /** + * Returns the current depth of the stack. + */ + public int size() { + return _list.size(); + } + + + /** + * Clears the stack. + */ + public void clear() { + _list.clear(); + } + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top of the stack. + * + * @return an char[] value + */ + public char[] toArray() { + char[] retval = _list.toArray(); + reverse( retval, 0, size() ); + return retval; + } + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top + * of the stack. + *

+ * If the native array is smaller than the stack depth, + * the native array will be filled with the elements from the top + * of the array until it is full and exclude the remainder. + * + * @param dest the array to copy into. + */ + public void toArray( char[] dest ) { + int size = size(); + int start = size - dest.length; + if ( start < 0 ) { + start = 0; + } + + int length = Math.min( size, dest.length ); + _list.toArray( dest, start, length ); + reverse( dest, 0, length ); + if ( dest.length > size ) { + dest[size] = _list.getNoEntryValue(); + } + } + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param dest the array of data + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + private void reverse( char[] dest, int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( dest, i, j ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param dest the array of data + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( char[] dest, int i, int j ) { + char tmp = dest[ i ]; + dest[ i ] = dest[ j ]; + dest[ j ] = tmp; + } + + + /** + * Returns a String representation of the list, top to bottom. + * + * @return a String value + */ + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = _list.size() - 1; i > 0; i-- ) { + buf.append( _list.get( i ) ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _list.get( 0 ) ); + } + buf.append( "}" ); + return buf.toString(); + } + + + public boolean equals( Object o ) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TCharArrayStack that = ( TCharArrayStack ) o; + + return _list.equals( that._list ); + } + + + public int hashCode() { + return _list.hashCode(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LIST + out.writeObject( _list ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + _list = ( TCharArrayList ) in.readObject(); + } +} // TCharArrayStack diff --git a/src/gnu/trove/stack/array/TDoubleArrayStack.java b/src/gnu/trove/stack/array/TDoubleArrayStack.java new file mode 100644 index 0000000..99c517d --- /dev/null +++ b/src/gnu/trove/stack/array/TDoubleArrayStack.java @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack.array; + +import gnu.trove.stack.TDoubleStack; +import gnu.trove.list.array.TDoubleArrayList; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A stack of double primitives, backed by a TDoubleArrayList + */ +public class TDoubleArrayStack implements TDoubleStack, Externalizable { + static final long serialVersionUID = 1L; + + /** the list used to hold the stack values. */ + protected TDoubleArrayList _list; + + public static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** + * Creates a new TDoubleArrayStack instance with the default + * capacity. + */ + public TDoubleArrayStack() { + this( DEFAULT_CAPACITY ); + } + + + /** + * Creates a new TDoubleArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + */ + public TDoubleArrayStack( int capacity ) { + _list = new TDoubleArrayList( capacity ); + } + + + /** + * Creates a new TDoubleArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + * @param no_entry_value value that represents null + */ + public TDoubleArrayStack( int capacity, double no_entry_value ) { + _list = new TDoubleArrayList( capacity, no_entry_value ); + } + + + /** + * Creates a new TDoubleArrayStack instance that is + * a copy of the instanced passed to us. + * + * @param stack the instance to copy + */ + public TDoubleArrayStack( TDoubleStack stack ) { + if ( stack instanceof TDoubleArrayStack ) { + TDoubleArrayStack array_stack = ( TDoubleArrayStack ) stack; + this._list = new TDoubleArrayList( array_stack._list ); + } else { + throw new UnsupportedOperationException( "Only support TDoubleArrayStack" ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public double getNoEntryValue() { + return _list.getNoEntryValue(); + } + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an double value + */ + public void push( double val ) { + _list.add( val ); + } + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an double value + */ + public double pop() { + return _list.removeAt( _list.size() - 1 ); + } + + + /** + * Returns the value at the top of the stack. + * + * @return an double value + */ + public double peek() { + return _list.get( _list.size() - 1 ); + } + + + /** + * Returns the current depth of the stack. + */ + public int size() { + return _list.size(); + } + + + /** + * Clears the stack. + */ + public void clear() { + _list.clear(); + } + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top of the stack. + * + * @return an double[] value + */ + public double[] toArray() { + double[] retval = _list.toArray(); + reverse( retval, 0, size() ); + return retval; + } + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top + * of the stack. + *

+ * If the native array is smaller than the stack depth, + * the native array will be filled with the elements from the top + * of the array until it is full and exclude the remainder. + * + * @param dest the array to copy into. + */ + public void toArray( double[] dest ) { + int size = size(); + int start = size - dest.length; + if ( start < 0 ) { + start = 0; + } + + int length = Math.min( size, dest.length ); + _list.toArray( dest, start, length ); + reverse( dest, 0, length ); + if ( dest.length > size ) { + dest[size] = _list.getNoEntryValue(); + } + } + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param dest the array of data + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + private void reverse( double[] dest, int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( dest, i, j ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param dest the array of data + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( double[] dest, int i, int j ) { + double tmp = dest[ i ]; + dest[ i ] = dest[ j ]; + dest[ j ] = tmp; + } + + + /** + * Returns a String representation of the list, top to bottom. + * + * @return a String value + */ + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = _list.size() - 1; i > 0; i-- ) { + buf.append( _list.get( i ) ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _list.get( 0 ) ); + } + buf.append( "}" ); + return buf.toString(); + } + + + public boolean equals( Object o ) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TDoubleArrayStack that = ( TDoubleArrayStack ) o; + + return _list.equals( that._list ); + } + + + public int hashCode() { + return _list.hashCode(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LIST + out.writeObject( _list ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + _list = ( TDoubleArrayList ) in.readObject(); + } +} // TDoubleArrayStack diff --git a/src/gnu/trove/stack/array/TFloatArrayStack.java b/src/gnu/trove/stack/array/TFloatArrayStack.java new file mode 100644 index 0000000..18f5acc --- /dev/null +++ b/src/gnu/trove/stack/array/TFloatArrayStack.java @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack.array; + +import gnu.trove.stack.TFloatStack; +import gnu.trove.list.array.TFloatArrayList; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A stack of float primitives, backed by a TFloatArrayList + */ +public class TFloatArrayStack implements TFloatStack, Externalizable { + static final long serialVersionUID = 1L; + + /** the list used to hold the stack values. */ + protected TFloatArrayList _list; + + public static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** + * Creates a new TFloatArrayStack instance with the default + * capacity. + */ + public TFloatArrayStack() { + this( DEFAULT_CAPACITY ); + } + + + /** + * Creates a new TFloatArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + */ + public TFloatArrayStack( int capacity ) { + _list = new TFloatArrayList( capacity ); + } + + + /** + * Creates a new TFloatArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + * @param no_entry_value value that represents null + */ + public TFloatArrayStack( int capacity, float no_entry_value ) { + _list = new TFloatArrayList( capacity, no_entry_value ); + } + + + /** + * Creates a new TFloatArrayStack instance that is + * a copy of the instanced passed to us. + * + * @param stack the instance to copy + */ + public TFloatArrayStack( TFloatStack stack ) { + if ( stack instanceof TFloatArrayStack ) { + TFloatArrayStack array_stack = ( TFloatArrayStack ) stack; + this._list = new TFloatArrayList( array_stack._list ); + } else { + throw new UnsupportedOperationException( "Only support TFloatArrayStack" ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public float getNoEntryValue() { + return _list.getNoEntryValue(); + } + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an float value + */ + public void push( float val ) { + _list.add( val ); + } + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an float value + */ + public float pop() { + return _list.removeAt( _list.size() - 1 ); + } + + + /** + * Returns the value at the top of the stack. + * + * @return an float value + */ + public float peek() { + return _list.get( _list.size() - 1 ); + } + + + /** + * Returns the current depth of the stack. + */ + public int size() { + return _list.size(); + } + + + /** + * Clears the stack. + */ + public void clear() { + _list.clear(); + } + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top of the stack. + * + * @return an float[] value + */ + public float[] toArray() { + float[] retval = _list.toArray(); + reverse( retval, 0, size() ); + return retval; + } + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top + * of the stack. + *

+ * If the native array is smaller than the stack depth, + * the native array will be filled with the elements from the top + * of the array until it is full and exclude the remainder. + * + * @param dest the array to copy into. + */ + public void toArray( float[] dest ) { + int size = size(); + int start = size - dest.length; + if ( start < 0 ) { + start = 0; + } + + int length = Math.min( size, dest.length ); + _list.toArray( dest, start, length ); + reverse( dest, 0, length ); + if ( dest.length > size ) { + dest[size] = _list.getNoEntryValue(); + } + } + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param dest the array of data + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + private void reverse( float[] dest, int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( dest, i, j ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param dest the array of data + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( float[] dest, int i, int j ) { + float tmp = dest[ i ]; + dest[ i ] = dest[ j ]; + dest[ j ] = tmp; + } + + + /** + * Returns a String representation of the list, top to bottom. + * + * @return a String value + */ + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = _list.size() - 1; i > 0; i-- ) { + buf.append( _list.get( i ) ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _list.get( 0 ) ); + } + buf.append( "}" ); + return buf.toString(); + } + + + public boolean equals( Object o ) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TFloatArrayStack that = ( TFloatArrayStack ) o; + + return _list.equals( that._list ); + } + + + public int hashCode() { + return _list.hashCode(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LIST + out.writeObject( _list ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + _list = ( TFloatArrayList ) in.readObject(); + } +} // TFloatArrayStack diff --git a/src/gnu/trove/stack/array/TIntArrayStack.java b/src/gnu/trove/stack/array/TIntArrayStack.java new file mode 100644 index 0000000..a7ff9ff --- /dev/null +++ b/src/gnu/trove/stack/array/TIntArrayStack.java @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack.array; + +import gnu.trove.stack.TIntStack; +import gnu.trove.list.array.TIntArrayList; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A stack of int primitives, backed by a TIntArrayList + */ +public class TIntArrayStack implements TIntStack, Externalizable { + static final long serialVersionUID = 1L; + + /** the list used to hold the stack values. */ + protected TIntArrayList _list; + + public static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** + * Creates a new TIntArrayStack instance with the default + * capacity. + */ + public TIntArrayStack() { + this( DEFAULT_CAPACITY ); + } + + + /** + * Creates a new TIntArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + */ + public TIntArrayStack( int capacity ) { + _list = new TIntArrayList( capacity ); + } + + + /** + * Creates a new TIntArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + * @param no_entry_value value that represents null + */ + public TIntArrayStack( int capacity, int no_entry_value ) { + _list = new TIntArrayList( capacity, no_entry_value ); + } + + + /** + * Creates a new TIntArrayStack instance that is + * a copy of the instanced passed to us. + * + * @param stack the instance to copy + */ + public TIntArrayStack( TIntStack stack ) { + if ( stack instanceof TIntArrayStack ) { + TIntArrayStack array_stack = ( TIntArrayStack ) stack; + this._list = new TIntArrayList( array_stack._list ); + } else { + throw new UnsupportedOperationException( "Only support TIntArrayStack" ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public int getNoEntryValue() { + return _list.getNoEntryValue(); + } + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an int value + */ + public void push( int val ) { + _list.add( val ); + } + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an int value + */ + public int pop() { + return _list.removeAt( _list.size() - 1 ); + } + + + /** + * Returns the value at the top of the stack. + * + * @return an int value + */ + public int peek() { + return _list.get( _list.size() - 1 ); + } + + + /** + * Returns the current depth of the stack. + */ + public int size() { + return _list.size(); + } + + + /** + * Clears the stack. + */ + public void clear() { + _list.clear(); + } + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top of the stack. + * + * @return an int[] value + */ + public int[] toArray() { + int[] retval = _list.toArray(); + reverse( retval, 0, size() ); + return retval; + } + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top + * of the stack. + *

+ * If the native array is smaller than the stack depth, + * the native array will be filled with the elements from the top + * of the array until it is full and exclude the remainder. + * + * @param dest the array to copy into. + */ + public void toArray( int[] dest ) { + int size = size(); + int start = size - dest.length; + if ( start < 0 ) { + start = 0; + } + + int length = Math.min( size, dest.length ); + _list.toArray( dest, start, length ); + reverse( dest, 0, length ); + if ( dest.length > size ) { + dest[size] = _list.getNoEntryValue(); + } + } + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param dest the array of data + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + private void reverse( int[] dest, int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( dest, i, j ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param dest the array of data + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( int[] dest, int i, int j ) { + int tmp = dest[ i ]; + dest[ i ] = dest[ j ]; + dest[ j ] = tmp; + } + + + /** + * Returns a String representation of the list, top to bottom. + * + * @return a String value + */ + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = _list.size() - 1; i > 0; i-- ) { + buf.append( _list.get( i ) ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _list.get( 0 ) ); + } + buf.append( "}" ); + return buf.toString(); + } + + + public boolean equals( Object o ) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TIntArrayStack that = ( TIntArrayStack ) o; + + return _list.equals( that._list ); + } + + + public int hashCode() { + return _list.hashCode(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LIST + out.writeObject( _list ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + _list = ( TIntArrayList ) in.readObject(); + } +} // TIntArrayStack diff --git a/src/gnu/trove/stack/array/TLongArrayStack.java b/src/gnu/trove/stack/array/TLongArrayStack.java new file mode 100644 index 0000000..79ebb9e --- /dev/null +++ b/src/gnu/trove/stack/array/TLongArrayStack.java @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack.array; + +import gnu.trove.stack.TLongStack; +import gnu.trove.list.array.TLongArrayList; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A stack of long primitives, backed by a TLongArrayList + */ +public class TLongArrayStack implements TLongStack, Externalizable { + static final long serialVersionUID = 1L; + + /** the list used to hold the stack values. */ + protected TLongArrayList _list; + + public static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** + * Creates a new TLongArrayStack instance with the default + * capacity. + */ + public TLongArrayStack() { + this( DEFAULT_CAPACITY ); + } + + + /** + * Creates a new TLongArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + */ + public TLongArrayStack( int capacity ) { + _list = new TLongArrayList( capacity ); + } + + + /** + * Creates a new TLongArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + * @param no_entry_value value that represents null + */ + public TLongArrayStack( int capacity, long no_entry_value ) { + _list = new TLongArrayList( capacity, no_entry_value ); + } + + + /** + * Creates a new TLongArrayStack instance that is + * a copy of the instanced passed to us. + * + * @param stack the instance to copy + */ + public TLongArrayStack( TLongStack stack ) { + if ( stack instanceof TLongArrayStack ) { + TLongArrayStack array_stack = ( TLongArrayStack ) stack; + this._list = new TLongArrayList( array_stack._list ); + } else { + throw new UnsupportedOperationException( "Only support TLongArrayStack" ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public long getNoEntryValue() { + return _list.getNoEntryValue(); + } + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an long value + */ + public void push( long val ) { + _list.add( val ); + } + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an long value + */ + public long pop() { + return _list.removeAt( _list.size() - 1 ); + } + + + /** + * Returns the value at the top of the stack. + * + * @return an long value + */ + public long peek() { + return _list.get( _list.size() - 1 ); + } + + + /** + * Returns the current depth of the stack. + */ + public int size() { + return _list.size(); + } + + + /** + * Clears the stack. + */ + public void clear() { + _list.clear(); + } + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top of the stack. + * + * @return an long[] value + */ + public long[] toArray() { + long[] retval = _list.toArray(); + reverse( retval, 0, size() ); + return retval; + } + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top + * of the stack. + *

+ * If the native array is smaller than the stack depth, + * the native array will be filled with the elements from the top + * of the array until it is full and exclude the remainder. + * + * @param dest the array to copy into. + */ + public void toArray( long[] dest ) { + int size = size(); + int start = size - dest.length; + if ( start < 0 ) { + start = 0; + } + + int length = Math.min( size, dest.length ); + _list.toArray( dest, start, length ); + reverse( dest, 0, length ); + if ( dest.length > size ) { + dest[size] = _list.getNoEntryValue(); + } + } + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param dest the array of data + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + private void reverse( long[] dest, int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( dest, i, j ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param dest the array of data + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( long[] dest, int i, int j ) { + long tmp = dest[ i ]; + dest[ i ] = dest[ j ]; + dest[ j ] = tmp; + } + + + /** + * Returns a String representation of the list, top to bottom. + * + * @return a String value + */ + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = _list.size() - 1; i > 0; i-- ) { + buf.append( _list.get( i ) ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _list.get( 0 ) ); + } + buf.append( "}" ); + return buf.toString(); + } + + + public boolean equals( Object o ) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TLongArrayStack that = ( TLongArrayStack ) o; + + return _list.equals( that._list ); + } + + + public int hashCode() { + return _list.hashCode(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LIST + out.writeObject( _list ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + _list = ( TLongArrayList ) in.readObject(); + } +} // TLongArrayStack diff --git a/src/gnu/trove/stack/array/TShortArrayStack.java b/src/gnu/trove/stack/array/TShortArrayStack.java new file mode 100644 index 0000000..eeccaca --- /dev/null +++ b/src/gnu/trove/stack/array/TShortArrayStack.java @@ -0,0 +1,287 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2001, Eric D. Friedman All Rights Reserved. +// Copyright (c) 2009, Rob Eden All Rights Reserved. +// Copyright (c) 2009, Jeff Randall All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + + +package gnu.trove.stack.array; + +import gnu.trove.stack.TShortStack; +import gnu.trove.list.array.TShortArrayList; +import gnu.trove.impl.*; + +import java.io.Externalizable; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.IOException; + + +////////////////////////////////////////////////// +// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! // +////////////////////////////////////////////////// + + +/** + * A stack of short primitives, backed by a TShortArrayList + */ +public class TShortArrayStack implements TShortStack, Externalizable { + static final long serialVersionUID = 1L; + + /** the list used to hold the stack values. */ + protected TShortArrayList _list; + + public static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY; + + + /** + * Creates a new TShortArrayStack instance with the default + * capacity. + */ + public TShortArrayStack() { + this( DEFAULT_CAPACITY ); + } + + + /** + * Creates a new TShortArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + */ + public TShortArrayStack( int capacity ) { + _list = new TShortArrayList( capacity ); + } + + + /** + * Creates a new TShortArrayStack instance with the + * specified capacity. + * + * @param capacity the initial depth of the stack + * @param no_entry_value value that represents null + */ + public TShortArrayStack( int capacity, short no_entry_value ) { + _list = new TShortArrayList( capacity, no_entry_value ); + } + + + /** + * Creates a new TShortArrayStack instance that is + * a copy of the instanced passed to us. + * + * @param stack the instance to copy + */ + public TShortArrayStack( TShortStack stack ) { + if ( stack instanceof TShortArrayStack ) { + TShortArrayStack array_stack = ( TShortArrayStack ) stack; + this._list = new TShortArrayList( array_stack._list ); + } else { + throw new UnsupportedOperationException( "Only support TShortArrayStack" ); + } + } + + + /** + * Returns the value that is used to represent null. The default + * value is generally zero, but can be changed during construction + * of the collection. + * + * @return the value that represents null + */ + public short getNoEntryValue() { + return _list.getNoEntryValue(); + } + + + /** + * Pushes the value onto the top of the stack. + * + * @param val an short value + */ + public void push( short val ) { + _list.add( val ); + } + + + /** + * Removes and returns the value at the top of the stack. + * + * @return an short value + */ + public short pop() { + return _list.removeAt( _list.size() - 1 ); + } + + + /** + * Returns the value at the top of the stack. + * + * @return an short value + */ + public short peek() { + return _list.get( _list.size() - 1 ); + } + + + /** + * Returns the current depth of the stack. + */ + public int size() { + return _list.size(); + } + + + /** + * Clears the stack. + */ + public void clear() { + _list.clear(); + } + + + /** + * Copies the contents of the stack into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top of the stack. + * + * @return an short[] value + */ + public short[] toArray() { + short[] retval = _list.toArray(); + reverse( retval, 0, size() ); + return retval; + } + + + /** + * Copies a slice of the list into a native array. Note that this will NOT + * pop them out of the stack. The front of the list will be the top + * of the stack. + *

+ * If the native array is smaller than the stack depth, + * the native array will be filled with the elements from the top + * of the array until it is full and exclude the remainder. + * + * @param dest the array to copy into. + */ + public void toArray( short[] dest ) { + int size = size(); + int start = size - dest.length; + if ( start < 0 ) { + start = 0; + } + + int length = Math.min( size, dest.length ); + _list.toArray( dest, start, length ); + reverse( dest, 0, length ); + if ( dest.length > size ) { + dest[size] = _list.getNoEntryValue(); + } + } + + + /** + * Reverse the order of the elements in the range of the list. + * + * @param dest the array of data + * @param from the inclusive index at which to start reversing + * @param to the exclusive index at which to stop reversing + */ + private void reverse( short[] dest, int from, int to ) { + if ( from == to ) { + return; // nothing to do + } + if ( from > to ) { + throw new IllegalArgumentException( "from cannot be greater than to" ); + } + for ( int i = from, j = to - 1; i < j; i++, j-- ) { + swap( dest, i, j ); + } + } + + + /** + * Swap the values at offsets i and j. + * + * @param dest the array of data + * @param i an offset into the data array + * @param j an offset into the data array + */ + private void swap( short[] dest, int i, int j ) { + short tmp = dest[ i ]; + dest[ i ] = dest[ j ]; + dest[ j ] = tmp; + } + + + /** + * Returns a String representation of the list, top to bottom. + * + * @return a String value + */ + public String toString() { + final StringBuilder buf = new StringBuilder( "{" ); + for ( int i = _list.size() - 1; i > 0; i-- ) { + buf.append( _list.get( i ) ); + buf.append( ", " ); + } + if ( size() > 0 ) { + buf.append( _list.get( 0 ) ); + } + buf.append( "}" ); + return buf.toString(); + } + + + public boolean equals( Object o ) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + TShortArrayStack that = ( TShortArrayStack ) o; + + return _list.equals( that._list ); + } + + + public int hashCode() { + return _list.hashCode(); + } + + + public void writeExternal( ObjectOutput out ) throws IOException { + // VERSION + out.writeByte( 0 ); + + // LIST + out.writeObject( _list ); + } + + + public void readExternal( ObjectInput in ) + throws IOException, ClassNotFoundException { + + // VERSION + in.readByte(); + + // LIST + _list = ( TShortArrayList ) in.readObject(); + } +} // TShortArrayStack diff --git a/src/gnu/trove/strategy/HashingStrategy.java b/src/gnu/trove/strategy/HashingStrategy.java new file mode 100644 index 0000000..29ff2ee --- /dev/null +++ b/src/gnu/trove/strategy/HashingStrategy.java @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, Eric D. Friedman All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/////////////////////////////////////////////////////////////////////////////// + +package gnu.trove.strategy; + +import java.io.Serializable; + + +/** + * Interface to support pluggable hashing strategies in maps and sets. + * Implementers can use this interface to make the trove hashing + * algorithms use object values, values provided by the java runtime, + * or a custom strategy when computing hashcodes. + * + * @author Eric Friedman + * @author Rob Eden + */ + +public interface HashingStrategy extends Serializable { + static final long serialVersionUID = 5674097166776615540L; + + /** + * Computes a hash code for the specified object. Implementers + * can use the object's own hashCode method, the Java + * runtime's identityHashCode, or a custom scheme. + * + * @param object for which the hashcode is to be computed + * @return the hashCode + */ + int computeHashCode( T object ); + + /** + * Compares o1 and o2 for equality. Strategy implementers may use + * the objects' own equals() methods, compare object references, + * or implement some custom scheme. + * + * @param o1 an Object value + * @param o2 an Object value + * @return true if the objects are equal according to this strategy. + */ + boolean equals( T o1, T o2 ); +} diff --git a/src/gnu/trove/strategy/IdentityHashingStrategy.java b/src/gnu/trove/strategy/IdentityHashingStrategy.java new file mode 100644 index 0000000..45d58ff --- /dev/null +++ b/src/gnu/trove/strategy/IdentityHashingStrategy.java @@ -0,0 +1,26 @@ +package gnu.trove.strategy; + +/** + * A {@link gnu.trove.strategy.HashingStrategy} that does identity comparisons + * (==) and uses {@link System#identityHashCode(Object)} for hashCode generation. + */ +public class IdentityHashingStrategy implements HashingStrategy { + static final long serialVersionUID = -5188534454583764904L; + + + /** + * A single instance that can be shared with multiple collections. + * This instance is thread safe. + */ + public static final IdentityHashingStrategy INSTANCE = + new IdentityHashingStrategy(); + + + public int computeHashCode( K object ) { + return System.identityHashCode( object ); + } + + public boolean equals( K o1, K o2 ) { + return o1 == o2; + } +} diff --git a/src/items.csv b/src/items.csv new file mode 100644 index 0000000..f5a7593 --- /dev/null +++ b/src/items.csv @@ -0,0 +1,7450 @@ +#version: TeamCity +#If you change this file, it will not be automatically updated after the next release. +#item,id,metadata +stone,1,0 +sstone,1,0 +smoothstone,1,0 +rock,1,0 +grass,2,0 +greendirt,2,0 +greenearth,2,0 +greenland,2,0 +dirt,3,0 +earth,3,0 +land,3,0 +grasslessdirt,3,1 +grasslessearth,3,1 +grasslessland,3,1 +podzol,3,2 +cobblestone,4,0 +cstone,4,0 +cobble,4,0 +wood,5,0 +plank,5,0 +woodenplank,5,0 +woodplank,5,0 +wplank,5,0 +plankwooden,5,0 +plankwood,5,0 +plankw,5,0 +oakplank,5,0 +oakwoodenplank,5,0 +oakwoodplank,5,0 +oakwplank,5,0 +oakplankwooden,5,0 +oakplankwood,5,0 +oakplankw,5,0 +oplank,5,0 +owoodenplank,5,0 +owoodplank,5,0 +owplank,5,0 +oplankwooden,5,0 +oplankwood,5,0 +oplankw,5,0 +pineplank,5,1 +pinewoodenplank,5,1 +pinewoodplank,5,1 +pinewplank,5,1 +pineplankwooden,5,1 +pineplankwood,5,1 +pineplankw,5,1 +pplank,5,1 +pwoodenplank,5,1 +pwoodplank,5,1 +pwplank,5,1 +pplankwooden,5,1 +pplankwood,5,1 +pplankw,5,1 +darkplank,5,1 +darkwoodenplank,5,1 +darkwoodplank,5,1 +darkwplank,5,1 +darkplankwooden,5,1 +darkplankwood,5,1 +darkplankw,5,1 +dplank,5,1 +dwoodenplank,5,1 +dwoodplank,5,1 +dwplank,5,1 +dplankwooden,5,1 +dplankwood,5,1 +dplankw,5,1 +spruceplank,5,1 +sprucewoodenplank,5,1 +sprucewoodplank,5,1 +sprucewplank,5,1 +spruceplankwooden,5,1 +spruceplankwood,5,1 +spruceplankw,5,1 +splank,5,1 +swoodenplank,5,1 +swoodplank,5,1 +swplank,5,1 +splankwooden,5,1 +splankwood,5,1 +splankw,5,1 +birchplank,5,2 +birchwoodenplank,5,2 +birchwoodplank,5,2 +birchwplank,5,2 +birchplankwooden,5,2 +birchplankwood,5,2 +birchplankw,5,2 +bplank,5,2 +bwoodenplank,5,2 +bwoodplank,5,2 +bwplank,5,2 +bplankwooden,5,2 +bplankwood,5,2 +bplankw,5,2 +lightplank,5,2 +lightwoodenplank,5,2 +lightwoodplank,5,2 +lightwplank,5,2 +lightplankwooden,5,2 +lightplankwood,5,2 +lightplankw,5,2 +lplank,5,2 +lwoodenplank,5,2 +lwoodplank,5,2 +lwplank,5,2 +lplankwooden,5,2 +lplankwood,5,2 +lplankw,5,2 +whiteplank,5,2 +whitewoodenplank,5,2 +whitewoodplank,5,2 +whitewplank,5,2 +whiteplankwooden,5,2 +whiteplankwood,5,2 +whiteplankw,5,2 +wwoodenplank,5,2 +wwoodplank,5,2 +wwplank,5,2 +wplankwooden,5,2 +wplankwood,5,2 +wplankw,5,2 +jungleplank,5,3 +junglewoodenplank,5,3 +junglewoodplank,5,3 +junglewplank,5,3 +jungleplankwooden,5,3 +jungleplankwood,5,3 +jungleplankw,5,3 +jplank,5,3 +jwoodenplank,5,3 +jwoodplank,5,3 +jwplank,5,3 +jplankwooden,5,3 +jplankwood,5,3 +jplankw,5,3 +forestplank,5,3 +forestwoodenplank,5,3 +forestwoodplank,5,3 +forestwplank,5,3 +forestplankwooden,5,3 +forestplankwood,5,3 +forestplankw,5,3 +fplank,5,3 +fwoodenplank,5,3 +fwoodplank,5,3 +fwplank,5,3 +fplankwooden,5,3 +fplankwood,5,3 +fplankw,5,3 +acaciaplank,5,4 +acaciawoodenplank,5,4 +acaciawoodplank,5,4 +acaciawplank,5,4 +acaciaplankwooden,5,4 +acaciaplankwood,5,4 +acaciaplankw,5,4 +aplank,5,4 +awoodenplank,5,4 +awoodplank,5,4 +awplank,5,4 +aplankwooden,5,4 +aplankwood,5,4 +aplankw,5,4 +darkoakplank,5,5 +darkoakwoodenplank,5,5 +darkoakwoodplank,5,5 +darkoakwplank,5,5 +darkoakplankwooden,5,5 +darkoakplankwood,5,5 +darkoakplankw,5,5 +doakplank,5,5 +doakwoodenplank,5,5 +doakwoodplank,5,5 +doakwplank,5,5 +doakplankwooden,5,5 +doakplankwood,5,5 +doakplankw,5,5 +doplank,5,5 +dowoodenplank,5,5 +dowoodplank,5,5 +dowplank,5,5 +doplankwooden,5,5 +doplankwood,5,5 +doplankw,5,5 +sapling,6,0 +treesapling,6,0 +logsapling,6,0 +trunksapling,6,0 +woodsapling,6,0 +oaktreesapling,6,0 +oaklogsapling,6,0 +oaktrunksapling,6,0 +oakwoodsapling,6,0 +osapling,6,0 +otreesapling,6,0 +ologsapling,6,0 +otrunksapling,6,0 +owoodsapling,6,0 +darksapling,6,1 +darktreesapling,6,1 +darklogsapling,6,1 +darktrunksapling,6,1 +darkwoodsapling,6,1 +sprucesapling,6,1 +sprucetreesapling,6,1 +sprucelogsapling,6,1 +sprucetrunksapling,6,1 +sprucewoodsapling,6,1 +pinesapling,6,1 +pinetreesapling,6,1 +pinelogsapling,6,1 +pinetrunksapling,6,1 +pinewoodsapling,6,1 +dsapling,6,1 +dtreesapling,6,1 +dlogsapling,6,1 +dtrunksapling,6,1 +dwoodsapling,6,1 +ssapling,6,1 +streesapling,6,1 +slogsapling,6,1 +strunksapling,6,1 +swoodsapling,6,1 +psapling,6,1 +ptreesapling,6,1 +plogsapling,6,1 +ptrunksapling,6,1 +pwoodsapling,6,1 +birchsapling,6,2 +birchtreesapling,6,2 +birchlogsapling,6,2 +birchtrunksapling,6,2 +birchwoodsapling,6,2 +lightsapling,6,2 +lighttreesapling,6,2 +lightlogsapling,6,2 +lighttrunksapling,6,2 +lightwoodsapling,6,2 +whitesapling,6,2 +whitetreesapling,6,2 +whitelogsapling,6,2 +whitetrunksapling,6,2 +whitewoodsapling,6,2 +bsapling,6,2 +btreesapling,6,2 +blogsapling,6,2 +btrunksapling,6,2 +bwoodsapling,6,2 +lsapling,6,2 +ltreesapling,6,2 +llogsapling,6,2 +ltrunksapling,6,2 +lwoodsapling,6,2 +wsapling,6,2 +wtreesapling,6,2 +wlogsapling,6,2 +wtrunksapling,6,2 +wwoodsapling,6,2 +junglesapling,6,3 +jungletreesapling,6,3 +junglelogsapling,6,3 +jungletrunksapling,6,3 +junglewoodsapling,6,3 +forestsapling,6,3 +foresttreesapling,6,3 +forestlogsapling,6,3 +foresttrunksapling,6,3 +forestwoodsapling,6,3 +jsapling,6,3 +jtreesapling,6,3 +jlogsapling,6,3 +jtrunksapling,6,3 +jwoodsapling,6,3 +fsapling,6,3 +ftreesapling,6,3 +flogsapling,6,3 +ftrunksapling,6,3 +fwoodsapling,6,3 +acaciasapling,6,4 +acaciatreesapling,6,4 +acacialogsapling,6,4 +acaciatrunksapling,6,4 +acaciawoodsapling,6,4 +asapling,6,4 +atreesapling,6,4 +alogsapling,6,4 +atrunksapling,6,4 +awoodsapling,6,4 +darkoaksapling,6,5 +darkoaktreesapling,6,5 +darkoaklogsapling,6,5 +darkoaktrunksapling,6,5 +darkoakwoodsapling,6,5 +doaksapling,6,5 +doaktreesapling,6,5 +doaklogsapling,6,5 +doaktrunksapling,6,5 +dosapling,6,5 +dowoodsapling,6,5 +dotreesapling,6,5 +dologsapling,6,5 +dotrunksapling,6,5 +bedrock,7,0 +oprock,7,0 +opblock,7,0 +adminblock,7,0 +adminrock,7,0 +adminium,7,0 +water,8,0 +stationarywater,9,0 +stillwater,9,0 +swater,9,0 +lava,10,0 +stationarylava,11,0 +stilllava,11,0 +slava,11,0 +sand,12,0 +redsand,12,1 +rsand,12,1 +gravel,13,0 +goldore,14,0 +oregold,14,0 +gore,14,0 +oreg,14,0 +ogold,14,0 +goldo,14,0 +ironore,15,0 +oreiron,15,0 +irono,15,0 +oiron,15,0 +steelore,15,0 +oresteel,15,0 +steelo,15,0 +osteel,15,0 +iore,15,0 +orei,15,0 +sore,15,0 +ores,15,0 +coalore,16,0 +orecoal,16,0 +coalo,16,0 +ocoal,16,0 +core,16,0 +tree,17,0 +log,17,0 +trunk,17,0 +oak,17,0 +oaktree,17,0 +oaklog,17,0 +oaktrunk,17,0 +oakwood,17,0 +otree,17,0 +olog,17,0 +otrunk,17,0 +owood,17,0 +pine,17,1 +pinetree,17,1 +pinelog,17,1 +pinetrunk,17,1 +pinewood,17,1 +darktree,17,1 +darklog,17,1 +darktrunk,17,1 +darkwood,17,1 +spruce,17,1 +sprucetree,17,1 +sprucelog,17,1 +sprucetrunk,17,1 +sprucewood,17,1 +dtree,17,1 +dlog,17,1 +dtrunk,17,1 +dwood,17,1 +stree,17,1 +slog,17,1 +strunk,17,1 +swood,17,1 +ptree,17,1 +plog,17,1 +ptrunk,17,1 +pwood,17,1 +birch,17,2 +birchtree,17,2 +birchlog,17,2 +birchtrunk,17,2 +birchwood,17,2 +whitetree,17,2 +whitelog,17,2 +whitetrunk,17,2 +whitewood,17,2 +lighttree,17,2 +lightlog,17,2 +lighttrunk,17,2 +lightwood,17,2 +btree,17,2 +blog,17,2 +btrunk,17,2 +bwood,17,2 +wtree,17,2 +wlog,17,2 +wtrunk,17,2 +wwood,17,2 +ltree,17,2 +llog,17,2 +ltrunk,17,2 +lwood,17,2 +jungletree,17,3 +junglelog,17,3 +jungletrunk,17,3 +junglewood,17,3 +jungle,17,3 +forest,17,3 +foresttree,17,3 +forestlog,17,3 +foresttrunk,17,3 +forestwood,17,3 +jtree,17,3 +jlog,17,3 +jtrunk,17,3 +jwood,17,3 +ftree,17,3 +flog,17,3 +ftrunk,17,3 +fwood,17,3 +leaves,18,0 +leaf,18,0 +treeleaves,18,0 +logleaves,18,0 +trunkleaves,18,0 +woodleaves,18,0 +oakleaves,18,0 +oakleaf,18,0 +oleaves,18,0 +oleaf,18,0 +oaktreeleaves,18,0 +oaklogleaves,18,0 +oaktrunkleaves,18,0 +oakwoodleaves,18,0 +otreeleaves,18,0 +ologleaves,18,0 +otrunkleaves,18,0 +owoodleaves,18,0 +treeleaf,18,0 +logleaf,18,0 +trunkleaf,18,0 +woodleaf,18,0 +oaktreeleaf,18,0 +oaklogleaf,18,0 +oaktrunkleaf,18,0 +oakwoodleaf,18,0 +otreeleaf,18,0 +ologleaf,18,0 +otrunkleaf,18,0 +owoodleaf,18,0 +pineleaves,18,1 +pineleaf,18,1 +pleaves,18,1 +pleaf,18,1 +pinetreeleaves,18,1 +pinelogleaves,18,1 +pinetrunkleaves,18,1 +pinewoodleaves,18,1 +ptreeleaves,18,1 +plogleaves,18,1 +ptrunkleaves,18,1 +pwoodleaves,18,1 +spruceleaves,18,1 +spruceleaf,18,1 +sleaves,18,1 +sleaf,18,1 +sprucetreeleaves,18,1 +sprucelogleaves,18,1 +sprucetrunkleaves,18,1 +sprucewoodleaves,18,1 +streeleaves,18,1 +slogleaves,18,1 +strunkleaves,18,1 +swoodleaves,18,1 +darkleaves,18,1 +darkleaf,18,1 +dleaves,18,1 +dleaf,18,1 +darktreeleaves,18,1 +darklogleaves,18,1 +darktrunkleaves,18,1 +darkwoodleaves,18,1 +dtreeleaves,18,1 +dlogleaves,18,1 +dtrunkleaves,18,1 +dwoodleaves,18,1 +sprucetreeleaf,18,1 +sprucelogleaf,18,1 +sprucetrunkleaf,18,1 +sprucewoodleaf,18,1 +streeleaf,18,1 +slogleaf,18,1 +strunkleaf,18,1 +swoodleaf,18,1 +pinetreeleaf,18,1 +pinelogleaf,18,1 +pinetrunkleaf,18,1 +pinewoodleaf,18,1 +ptreeleaf,18,1 +plogleaf,18,1 +ptrunkleaf,18,1 +pwoodleaf,18,1 +darktreeleaf,18,1 +darklogleaf,18,1 +darktrunkleaf,18,1 +darkwoodleaf,18,1 +dtreeleaf,18,1 +dlogleaf,18,1 +dtrunkleaf,18,1 +dwoodleaf,18,1 +birchleaves,18,2 +birchleaf,18,2 +bleaves,18,2 +bleaf,18,2 +birchtreeleaves,18,2 +birchlogleaves,18,2 +birchtrunkleaves,18,2 +birchwoodleaves,18,2 +btreeleaves,18,2 +blogleaves,18,2 +btrunkleaves,18,2 +bwoodleaves,18,2 +lightleaves,18,2 +lightleaf,18,2 +lleaves,18,2 +lleaf,18,2 +lighttreeleaves,18,2 +lightlogleaves,18,2 +lighttrunkleaves,18,2 +lightwoodleaves,18,2 +ltreeleaves,18,2 +llogleaves,18,2 +ltrunkleaves,18,2 +lwoodleaves,18,2 +whiteleaves,18,2 +whiteleaf,18,2 +wleaves,18,2 +wleaf,18,2 +whitetreeleaves,18,2 +whitelogleaves,18,2 +whitetrunkleaves,18,2 +whitewoodleaves,18,2 +wtreeleaves,18,2 +wlogleaves,18,2 +wtrunkleaves,18,2 +wwoodleaves,18,2 +birchtreeleaf,18,2 +birchlogleaf,18,2 +birchtrunkleaf,18,2 +birchwoodleaf,18,2 +btreeleaf,18,2 +blogleaf,18,2 +btrunkleaf,18,2 +bwoodleaf,18,2 +lighttreeleaf,18,2 +lightlogleaf,18,2 +lighttrunkleaf,18,2 +lightwoodleaf,18,2 +ltreeleaf,18,2 +llogleaf,18,2 +ltrunkleaf,18,2 +lwoodleaf,18,2 +whitetreeleaf,18,2 +whitelogleaf,18,2 +whitetrunkleaf,18,2 +whitewoodleaf,18,2 +wtreeleaf,18,2 +wlogleaf,18,2 +wtrunkleaf,18,2 +wwoodleaf,18,2 +jungleleaves,18,3 +jungleleaf,18,3 +jleaves,18,3 +jleaf,18,3 +jungletreeleaves,18,3 +junglelogleaves,18,3 +jungletrunkleaves,18,3 +junglewoodleaves,18,3 +jtreeleaves,18,3 +jlogleaves,18,3 +jtrunkleaves,18,3 +jwoodleaves,18,3 +forestleaves,18,3 +forestleaf,18,3 +fleaves,18,3 +fleaf,18,3 +foresttreeleaves,18,3 +forestlogleaves,18,3 +foresttrunkleaves,18,3 +forestwoodleaves,18,3 +ftreeleaves,18,3 +flogleaves,18,3 +ftrunkleaves,18,3 +fwoodleaves,18,3 +jungletreeleaf,18,3 +junglelogleaf,18,3 +jungletrunkleaf,18,3 +junglewoodleaf,18,3 +jtreeleaf,18,3 +jlogleaf,18,3 +jtrunkleaf,18,3 +jwoodleaf,18,3 +foresttreeleaf,18,3 +forestlogleaf,18,3 +foresttrunkleaf,18,3 +forestwoodleaf,18,3 +ftreeleaf,18,3 +flogleaf,18,3 +ftrunkleaf,18,3 +fwoodleaf,18,3 +sponge,19,0 +glass,20,0 +blockglass,20,0 +glassblock,20,0 +lapislazuliore,21,0 +lapislazulio,21,0 +orelapislazuli,21,0 +olapislazuli,21,0 +lapisore,21,0 +lapiso,21,0 +orelapis,21,0 +olapis,21,0 +lore,21,0 +orel,21,0 +lapislazuliblock,22,0 +blocklapislazuli,22,0 +lapisblock,22,0 +blocklapis,22,0 +lblock,22,0 +blockl,22,0 +dispenser,23,0 +dispense,23,0 +sandstone,24,0 +sastone,24,0 +creepersandstone,24,1 +creepersastone,24,1 +creepsandstone,24,1 +creepsastone,24,1 +csandstone,24,1 +csastone,24,1 +hieroglyphicsandstone,24,1 +hieroglyphicsastone,24,1 +hieroglyphsandstone,24,1 +hieroglyphsastone,24,1 +hsandstone,24,1 +hsastone,24,1 +pyramidsandstone,24,1 +pyramidsastone,24,1 +psandstone,24,1 +psastone,24,1 +chiseledsandstone,24,1 +chiseledsastone,24,1 +chiselsandstone,24,1 +chiselsastone,24,1 +smoothsandstone,24,2 +smoothsastone,24,2 +ssandstone,24,2 +smsastone,24,2 +ssastone,24,2 +noteblock,25,0 +musicblock,25,0 +nblock,25,0 +mblock,25,0 +poweredtrack,27,0 +poweredrails,27,0 +poweredrail,27,0 +boostertrack,27,0 +boosterrails,27,0 +boosterrail,27,0 +powertrack,27,0 +powerrails,27,0 +powerrail,27,0 +boosttrack,27,0 +boostrails,27,0 +boostrail,27,0 +ptrack,27,0 +prails,27,0 +prail,27,0 +btrack,27,0 +brails,27,0 +brail,27,0 +detectortrack,28,0 +detectorrails,28,0 +detectorrail,28,0 +detectingtrack,28,0 +detectingrails,28,0 +detectingrail,28,0 +detecttrack,28,0 +detectrails,28,0 +detectrail,28,0 +dtrack,28,0 +drails,28,0 +drail,28,0 +stickypistonbase,29,0 +stickypiston,29,0 +stickpistonbase,29,0 +stickpiston,29,0 +stickyp,29,0 +spistonbase,29,0 +spiston,29,0 +pistonstickybase,29,0 +pistonsticky,29,0 +pistonstickbase,29,0 +pistonstick,29,0 +pistonsbase,29,0 +pistons,29,0 +psticky,29,0 +pstick,29,0 +spiderweb,30,0 +cobweb,30,0 +sweb,30,0 +cweb,30,0 +web,30,0 +longgrass,31,1 +tallgrass,31,1 +wildgrass,31,1 +grasslong,31,1 +grasstall,31,1 +grasswild,31,1 +lgrass,31,1 +tgrass,31,1 +wgrass,31,1 +fern,31,2 +bush,31,2 +deadshrub,32,0 +dshrub,32,0 +deadbush,32,0 +dbush,32,0 +deadsapling,32,0 +piston,33,0 +pistonbase,33,0 +pistonblock,33,0 +whitewool,35,0 +whitecloth,35,0 +whitecotton,35,0 +wcloth,35,0 +wwool,35,0 +wcotton,35,0 +cloth,35,0 +wool,35,0 +cotton,35,0 +orangewool,35,1 +orangecloth,35,1 +orangecotton,35,1 +ocloth,35,1 +owool,35,1 +ocotton,35,1 +magentawool,35,2 +magentacloth,35,2 +magentacotton,35,2 +mcloth,35,2 +mwool,35,2 +mcotton,35,2 +lightbluewool,35,3 +lightbluecloth,35,3 +lightbluecotton,35,3 +lbluecloth,35,3 +lbluewool,35,3 +lbluecotton,35,3 +lightblucloth,35,3 +lightbluwool,35,3 +lightblucotton,35,3 +lblucloth,35,3 +lbluwool,35,3 +lblucotton,35,3 +lbcloth,35,3 +lbwool,35,3 +lbcotton,35,3 +yellowwool,35,4 +yellowcloth,35,4 +yellowcotton,35,4 +ycloth,35,4 +ywool,35,4 +ycotton,35,4 +lightgreenwool,35,5 +lightgreencloth,35,5 +lightgreencotton,35,5 +lgreencloth,35,5 +lgreenwool,35,5 +lgreencotton,35,5 +lightgrecloth,35,5 +lightgrewool,35,5 +lightgrecotton,35,5 +lgrecloth,35,5 +lgrewool,35,5 +lgrecotton,35,5 +limecloth,35,5 +limewool,35,5 +limecotton,35,5 +lcloth,35,5 +lwool,35,5 +lcotton,35,5 +pinkwool,35,6 +pinkcloth,35,6 +pinkcotton,35,6 +picloth,35,6 +piwool,35,6 +picotton,35,6 +darkgraywool,35,7 +darkgraycloth,35,7 +darkgraycotton,35,7 +darkgreywool,35,7 +darkgreycloth,35,7 +darkgreycotton,35,7 +dgraycloth,35,7 +dgraywool,35,7 +dgraycotton,35,7 +dgreycloth,35,7 +dgreywool,35,7 +dgreycotton,35,7 +darkgracloth,35,7 +darkgrawool,35,7 +darkgracotton,35,7 +dgracloth,35,7 +dgrawool,35,7 +dgracotton,35,7 +graycloth,35,7 +graywool,35,7 +graycotton,35,7 +greycloth,35,7 +greywool,35,7 +greycotton,35,7 +gracloth,35,7 +grawool,35,7 +gracotton,35,7 +lightgraywool,35,8 +lightgraycloth,35,8 +lightgraycotton,35,8 +lgraycloth,35,8 +lgraywool,35,8 +lgraycotton,35,8 +lightgreywool,35,8 +lightgreycloth,35,8 +lightgreycotton,35,8 +lgreycloth,35,8 +lgreywool,35,8 +lgreycotton,35,8 +lightgracloth,35,8 +lightgrawool,35,8 +lightgracotton,35,8 +lgracloth,35,8 +lgrawool,35,8 +lgracotton,35,8 +silvercloth,35,8 +silverwool,35,8 +silvercotton,35,8 +sicloth,35,8 +siawool,35,8 +siacotton,35,8 +cyanwool,35,9 +cyancloth,35,9 +cyancotton,35,9 +ccloth,35,9 +cwool,35,9 +ccotton,35,9 +purplewool,35,10 +purplecloth,35,10 +purplecotton,35,10 +pucloth,35,10 +puwool,35,10 +pucotton,35,10 +bluewool,35,11 +bluecloth,35,11 +bluecotton,35,11 +blucloth,35,11 +bluwool,35,11 +blucotton,35,11 +brownwool,35,12 +browncloth,35,12 +browncotton,35,12 +brocloth,35,12 +browool,35,12 +brocotton,35,12 +darkgreenwool,35,13 +darkgreencloth,35,13 +darkgreencotton,35,13 +dgreencloth,35,13 +dgreenwool,35,13 +dgreencotton,35,13 +greencloth,35,13 +greenwool,35,13 +greencotton,35,13 +darkgrecloth,35,13 +darkgrewool,35,13 +darkgrecotton,35,13 +dgrecloth,35,13 +dgrewool,35,13 +dgrecotton,35,13 +grecloth,35,13 +grewool,35,13 +grecotton,35,13 +redwool,35,14 +redcloth,35,14 +redcotton,35,14 +rcloth,35,14 +rwool,35,14 +rcotton,35,14 +blackwool,35,15 +blackcloth,35,15 +blackcotton,35,15 +blacloth,35,15 +blawool,35,15 +blacotton,35,15 +dandelion,37,0 +yellowdandelion,37,0 +ydandelion,37,0 +yellowflower,37,0 +yflower,37,0 +flower,37,0 +rose,38,0 +redrose,38,0 +rrose,38,0 +redflower,38,0 +rflower,38,0 +poppy,38,0 +redpoppy,38,0 +blueorchid,38,1 +cyanorchid,38,1 +lightblueorchid,38,1 +lblueorchid,38,1 +orchid,38,1 +allium,38,2 +magentaallium,38,2 +azurebluet,38,3 +whiteazurebluet,38,3 +abluet,38,3 +azureb,38,3 +houstonia,38,3 +redtulip,38,4 +tulipred,38,4 +rtulip,38,4 +tulipr,38,4 +orangetulip,38,5 +tuliporange,38,5 +otulip,38,5 +tulipo,38,5 +whitetulip,38,6 +tulipwhite,38,6 +wtulip,38,6 +tulipw,38,6 +pinktulip,38,7 +tulippink,38,7 +ptulip,38,7 +tulipp,38,7 +oxeye,38,8 +daisy,38,8 +oxeyedaisy,38,8 +daisyoxeye,38,8 +moondaisy,38,8 +daisymoon,38,8 +lightgrayoxeye,38,8 +lgrayoxeye,38,8 +lightgreyoxeye,38,8 +lgreyoxeye,38,8 +brownmushroom,39,0 +brownshroom,39,0 +brownmush,39,0 +bmushroom,39,0 +bshroom,39,0 +bmush,39,0 +redmushroom,40,0 +redshroom,40,0 +redmush,40,0 +rmushroom,40,0 +rshroom,40,0 +rmush,40,0 +goldblock,41,0 +blockgold,41,0 +gblock,41,0 +blockg,41,0 +ironblock,42,0 +steelblock,42,0 +blockiron,42,0 +blocksteel,42,0 +iblock,42,0 +stblock,42,0 +blocki,42,0 +blockst,42,0 +stonedoublestep,43,0 +stonedstep,43,0 +sdoublestep,43,0 +sdstep,43,0 +doublestonestep,43,0 +dstonestep,43,0 +doublesstep,43,0 +doublestep,43,0 +dstep,43,0 +stonedoubleslab,43,0 +stonedslab,43,0 +sdoubleslab,43,0 +sdslab,43,0 +doublestoneslab,43,0 +dstoneslab,43,0 +doublesslab,43,0 +doubleslab,43,0 +dslab,43,0 +stonedoublehalfblock,43,0 +stonedhalfblock,43,0 +sdoublehalfblock,43,0 +sdhalfblock,43,0 +doublestonehalfblock,43,0 +dstonehalfblock,43,0 +doubleshalfblock,43,0 +doublehalfblock,43,0 +dhalfblock,43,0 +sandstonedoublestep,43,1 +sandstonedstep,43,1 +sstonedoublestep,43,1 +sstonedstep,43,1 +ssdoublestep,43,1 +ssdstep,43,1 +doublesandstonestep,43,1 +dsandstonestep,43,1 +doublesstonestep,43,1 +dsstonestep,43,1 +doublessstep,43,1 +dsstep,43,1 +sandstonedoubleslab,43,1 +sandstonedslab,43,1 +sstonedoubleslab,43,1 +sstonedslab,43,1 +ssdoubleslab,43,1 +ssdslab,43,1 +doublesandstoneslab,43,1 +dsandstoneslab,43,1 +doublesstoneslab,43,1 +dsstoneslab,43,1 +doublessslab,43,1 +dsslab,43,1 +sandstonedoublehalfblock,43,1 +sandstonedhalfblock,43,1 +sstonedoublehalfblock,43,1 +sstonedhalfblock,43,1 +ssdoublehalfblock,43,1 +ssdhalfblock,43,1 +doublesandstonehalfblock,43,1 +dsandstonehalfblock,43,1 +doublesstonehalfblock,43,1 +dsstonehalfblock,43,1 +doublesshalfblock,43,1 +dsshalfblock,43,1 +plankstonedoublestep,43,2 +woodenstonedoublestep,43,2 +woodenstonedstep,43,2 +woodstonedoublestep,43,2 +woodstonedstep,43,2 +wstonedoublestep,43,2 +wstonedstep,43,2 +doublewoodenstonestep,43,2 +dwoodenstonestep,43,2 +doublewoodstonestep,43,2 +dwoodstonestep,43,2 +doublewstonestep,43,2 +dwstonestep,43,2 +woodenstonedoubleslab,43,2 +woodenstonedslab,43,2 +woodstonedoubleslab,43,2 +woodstonedslab,43,2 +wstonedoubleslab,43,2 +wstonedslab,43,2 +doublewoodenstoneslab,43,2 +dwoodenstoneslab,43,2 +doublewoodstoneslab,43,2 +dwoodstoneslab,43,2 +doublewstoneslab,43,2 +dwstoneslab,43,2 +woodenstonedoublehalfblock,43,2 +woodenstonedhalfblock,43,2 +woodstonedoublehalfblock,43,2 +woodstonedhalfblock,43,2 +wstonedoublehalfblock,43,2 +wstonedhalfblock,43,2 +doublewoodenstonehalfblock,43,2 +dwoodenstonehalfblock,43,2 +doublewoodstonehalfblock,43,2 +dwoodstonehalfblock,43,2 +doublewstonehalfblock,43,2 +dwstonehalfblock,43,2 +cobblestonedoublestep,43,3 +cobblestonedstep,43,3 +cobbledoublestep,43,3 +cobbledstep,43,3 +cstonedoublestep,43,3 +cstonedstep,43,3 +csdoublestep,43,3 +csdstep,43,3 +doublecobblestonestep,43,3 +dcobblestonestep,43,3 +doublecobblestep,43,3 +dcobblestep,43,3 +doublecstonestep,43,3 +dcstonestep,43,3 +doublecsstep,43,3 +dcsstep,43,3 +cobblestonedoubleslab,43,3 +cobblestonedslab,43,3 +cobbledoubleslab,43,3 +cobbledslab,43,3 +cstonedoubleslab,43,3 +cstonedslab,43,3 +csdoubleslab,43,3 +csdslab,43,3 +doublecobblestoneslab,43,3 +dcobblestoneslab,43,3 +doublecobbleslab,43,3 +dcobbleslab,43,3 +doublecstoneslab,43,3 +dcstoneslab,43,3 +doublecsslab,43,3 +dcsslab,43,3 +cobblestonedoublehalfblock,43,3 +cobblestonedhalfblock,43,3 +cobbledoublehalfblock,43,3 +cobbledhalfblock,43,3 +cstonedoublehalfblock,43,3 +cstonedhalfblock,43,3 +csdoublehalfblock,43,3 +csdhalfblock,43,3 +doublecobblestonehalfblock,43,3 +dcobblestonehalfblock,43,3 +doublecobblehalfblock,43,3 +dcobblehalfblock,43,3 +doublecstonehalfblock,43,3 +dcstonehalfblock,43,3 +doublecshalfblock,43,3 +dcshalfblock,43,3 +brickdoublestep,43,4 +brickdstep,43,4 +bdoublestep,43,4 +bdstep,43,4 +brickdoubleslab,43,4 +brickdslab,43,4 +bdoubleslab,43,4 +bdslab,43,4 +doublebrickstep,43,4 +dbrickstep,43,4 +doublebstep,43,4 +dbstep,43,4 +doublebrickslab,43,4 +dbrickslab,43,4 +doublebslab,43,4 +dbslab,43,4 +brickdoublehalfblock,43,4 +brickdhalfblock,43,4 +bdoublehalfblock,43,4 +bdhalfblock,43,4 +doublebrickhalfblock,43,4 +dbrickhalfblock,43,4 +doublebhalfblock,43,4 +dbhalfblock,43,4 +stonebrickdoublestep,43,5 +stonebrickdstep,43,5 +stonebdoublestep,43,5 +stonebdstep,43,5 +sbrickdoublestep,43,5 +sbrickdstep,43,5 +sbdoublestep,43,5 +sbdstep,43,5 +stonebrickdoubleslab,43,5 +stonebrickdslab,43,5 +stonebdoubleslab,43,5 +stonebdslab,43,5 +sbrickdoubleslab,43,5 +sbrickdslab,43,5 +sbdoubleslab,43,5 +sbdslab,43,5 +doublestonebrickstep,43,5 +dstonebrickstep,43,5 +doublestonebstep,43,5 +dstonebstep,43,5 +doublesbrickstep,43,5 +dsbrickstep,43,5 +doublesbstep,43,5 +dsbstep,43,5 +doublestonebrickslab,43,5 +dstonebrickslab,43,5 +doublestonebslab,43,5 +dstonebslab,43,5 +doublesbrickslab,43,5 +dsbrickdslab,43,5 +doublesbslab,43,5 +dsbslab,43,5 +stonebrickdoublehalfblock,43,5 +stonebrickdhalfblock,43,5 +stonebdoublehalfblock,43,5 +stonebdhalfblock,43,5 +sbrickdoublehalfblock,43,5 +sbrickdhalfblock,43,5 +sbdoublehalfblock,43,5 +sbdhalfblock,43,5 +doublestonebrickhalfblock,43,5 +dstonebrickhalfblock,43,5 +doublestonebhalfblock,43,5 +dstonebhalfblock,43,5 +doublesbrickhalfblock,43,5 +dsbrickhalfblock,43,5 +doublesbhalfblock,43,5 +dsbhalfblock,43,5 +netherbrickdoubleslab,43,6 +hellbrickdoubleslab,43,6 +nbrickdoubleslab,43,6 +hbrickdoubleslab,43,6 +netherdoubleslab,43,6 +helldoubleslab,43,6 +nbdoubleslab,43,6 +hbdoubleslab,43,6 +hdoubleslab,43,6 +ndoubleslab,43,6 +netherbrickdoublestep,43,6 +hellbrickdoublestep,43,6 +nbrickdoublestep,43,6 +hbrickdoublestep,43,6 +netherdoublestep,43,6 +helldoublestep,43,6 +nbdoublestep,43,6 +hbdoublestep,43,6 +ndoublestep,43,6 +hdoublestep,43,6 +netherbrickdoublehalfblock,43,6 +hellbrickdoublehalfblock,43,6 +nbrickdoublehalfblock,43,6 +hbrickdoublehalfblock,43,6 +netherdoublehalfblock,43,6 +helldoublehalfblock,43,6 +nbdoublehalfblock,43,6 +hbdoublehalfblock,43,6 +ndoublehalfblock,43,6 +hdoublehalfblock,43,6 +netherbrickdslab,43,6 +hellbrickdslab,43,6 +nbrickdslab,43,6 +hbrickdslab,43,6 +netherdslab,43,6 +helldslab,43,6 +nbdslab,43,6 +hbdslab,43,6 +hdslab,43,6 +ndslab,43,6 +netherbrickdstep,43,6 +hellbrickdstep,43,6 +nbrickdstep,43,6 +hbrickdstep,43,6 +netherdstep,43,6 +helldstep,43,6 +nbdstep,43,6 +hbdstep,43,6 +ndstep,43,6 +hdstep,43,6 +netherbrickdhalfblock,43,6 +hellbrickdhalfblock,43,6 +nbrickdhalfblock,43,6 +hbrickdhalfblock,43,6 +netherdhalfblock,43,6 +helldhalfblock,43,6 +nbdhalfblock,43,6 +hbdhalfblock,43,6 +ndhalfblock,43,6 +hdhalfblock,43,6 +doublenetherbrickslab,43,6 +doublehellbrickslab,43,6 +doublenbrickslab,43,6 +doublehbrickslab,43,6 +doublenetherslab,43,6 +doublehellslab,43,6 +doublenbslab,43,6 +doublehbslab,43,6 +doublehslab,43,6 +doublenslab,43,6 +doublenetherbrickstep,43,6 +doublehellbrickstep,43,6 +doublenbrickstep,43,6 +doublehbrickstep,43,6 +doublenetherstep,43,6 +doublehellstep,43,6 +doublenbstep,43,6 +doublehbstep,43,6 +doublenstep,43,6 +doublehstep,43,6 +doublenetherbrickhalfblock,43,6 +doublehellbrickhalfblock,43,6 +doublenbrickhalfblock,43,6 +doublehbrickhalfblock,43,6 +doublenetherhalfblock,43,6 +doublehellhalfblock,43,6 +doublenbhalfblock,43,6 +doublehbhalfblock,43,6 +doublenhalfblock,43,6 +doublehhalfblock,43,6 +dnetherbrickslab,43,6 +dhellbrickslab,43,6 +dnbrickslab,43,6 +dhbrickslab,43,6 +dnetherslab,43,6 +dhellslab,43,6 +dnbslab,43,6 +dhbslab,43,6 +dhslab,43,6 +dnslab,43,6 +dnetherbrickstep,43,6 +dhellbrickstep,43,6 +dnbrickstep,43,6 +dhbrickstep,43,6 +dnetherstep,43,6 +dhellstep,43,6 +dnbstep,43,6 +dhbstep,43,6 +dnstep,43,6 +dhstep,43,6 +dnetherbrickhalfblock,43,6 +dhellbrickhalfblock,43,6 +dnbrickhalfblock,43,6 +dhbrickhalfblock,43,6 +dnetherhalfblock,43,6 +dhellhalfblock,43,6 +dnbhalfblock,43,6 +dhbhalfblock,43,6 +dnhalfblock,43,6 +dhhalfblock,43,6 +netherquartzdoublestep,43,7 +hellquartzdoublestep,43,7 +deathquartzdoublestep,43,7 +nquartzdoublestep,43,7 +hquartzdoublestep,43,7 +dquartzdoublestep,43,7 +quartzdoublestep,43,7 +nqdoublestep,43,7 +hqdoublestep,43,7 +dqdoublestep,43,7 +qdoublestep,43,7 +netherquartzdoubleslab,43,7 +hellquartzdoubleslab,43,7 +deathquartzdoubleslab,43,7 +nquartzdoubleslab,43,7 +hquartzdoubleslab,43,7 +dquartzdoubleslab,43,7 +quartzdoubleslab,43,7 +nqdoubleslab,43,7 +hqdoubleslab,43,7 +dqdoubleslab,43,7 +qdoubleslab,43,7 +netherquartzdoublehalfblock,43,7 +hellquartzdoublehalfblock,43,7 +deathquartzdoublehalfblock,43,7 +nquartzdoublehalfblock,43,7 +hquartzdoublehalfblock,43,7 +dquartzdoublehalfblock,43,7 +quartzdoublehalfblock,43,7 +nqdoublehalfblock,43,7 +hqdoublehalfblock,43,7 +dqdoublehalfblock,43,7 +qdoublehalfblock,43,7 +netherquartzdslab,43,7 +hellquartzdslab,43,7 +deathquartzdslab,43,7 +nquartzdslab,43,7 +hquartzdslab,43,7 +dquartzdslab,43,7 +quartzdslab,43,7 +nqdslab,43,7 +hqdslab,43,7 +dqdslab,43,7 +qdslab,43,7 +netherquartzdstep,43,7 +hellquartzdstep,43,7 +deathquartzdstep,43,7 +nquartzdstep,43,7 +hquartzdstep,43,7 +dquartzdstep,43,7 +quartzdstep,43,7 +nqdstep,43,7 +hqdstep,43,7 +dqdstep,43,7 +qdstep,43,7 +netherquartzdhalfblock,43,7 +hellquartzdhalfblock,43,7 +deathquartzdhalfblock,43,7 +nquartzdhalfblock,43,7 +hquartzdhalfblock,43,7 +dquartzdhalfblock,43,7 +quartzdhalfblock,43,7 +nqdhalfblock,43,7 +hqdhalfblock,43,7 +dqdhalfblock,43,7 +qdhalfblock,43,7 +doublenetherquartzslab,43,7 +doublehellquartzslab,43,7 +doubledeathquartzslab,43,7 +doublenquartzslab,43,7 +doublehquartzslab,43,7 +doubledquartzslab,43,7 +doublequartzslab,43,7 +doublenqslab,43,7 +doublehqslab,43,7 +doubledqslab,43,7 +doubleqslab,43,7 +doublenetherquartzstep,43,7 +doublehellquartzstep,43,7 +doubledeathquartzstep,43,7 +doublenquartzstep,43,7 +doublehquartzstep,43,7 +doubledquartzstep,43,7 +doublequartzstep,43,7 +doublenqstep,43,7 +doublehqstep,43,7 +doubledqstep,43,7 +doubleqstep,43,7 +doublenetherquartzhalfblock,43,7 +doublehellquartzhalfblock,43,7 +doubledeathquartzhalfblock,43,7 +doublenquartzhalfblock,43,7 +doublehquartzhalfblock,43,7 +doubledquartzhalfblock,43,7 +doublequartzhalfblock,43,7 +doublenqhalfblock,43,7 +doublehqhalfblock,43,7 +doubledqhalfblock,43,7 +doubleqhalfblock,43,7 +dnetherquartzslab,43,7 +dhellquartzslab,43,7 +ddeathquartzslab,43,7 +dnquartzslab,43,7 +dhquartzslab,43,7 +ddquartzslab,43,7 +dnqslab,43,7 +dhqslab,43,7 +ddqslab,43,7 +dnetherquartzstep,43,7 +dhellquartzstep,43,7 +ddeathquartzstep,43,7 +dnquartzstep,43,7 +dhquartzstep,43,7 +ddquartzstep,43,7 +dnqstep,43,7 +dhqstep,43,7 +ddqstep,43,7 +dnetherquartzhalfblock,43,7 +dhellquartzhalfblock,43,7 +ddeathquartzhalfblock,43,7 +dnquartzhalfblock,43,7 +dhquartzhalfblock,43,7 +ddquartzhalfblock,43,7 +dnqhalfblock,43,7 +dhqhalfblock,43,7 +ddqhalfblock,43,7 +smoothstonedoubleslab,43,8 +smoothstonedoublestep,43,8 +smoothstonedoublehalfblock,43,8 +smoothstonedslab,43,8 +smoothstonedstep,43,8 +smoothstonedhalfblock,43,8 +doublesmoothstoneslab,43,8 +doublesmoothstonestep,43,8 +doublesmoothstonehalfblock,43,8 +dsmoothstoneslab,43,8 +dsmoothstonestep,43,8 +dsmoothstonehalfblock,43,8 +smoothsandstonedoubleslab,43,9 +ssandstonedoubleslab,43,9 +ssstonedoubleslab,43,9 +sssdoubleslab,43,9 +smoothsandstonedoublestep,43,9 +ssandstonedoublestep,43,9 +ssstonedoublestep,43,9 +sssdoublestep,43,9 +smoothsandstonedoublehalfblock,43,9 +ssandstonedoublehalfblock,43,9 +ssstonedoublehalfblock,43,9 +sssdoublehalfblock,43,9 +smoothsandstonedslab,43,9 +ssandstonedslab,43,9 +ssstonedslab,43,9 +sssdslab,43,9 +smoothsandstonedstep,43,9 +ssandstonedstep,43,9 +ssstonedstep,43,9 +sssdstep,43,9 +smoothsandstonedhalfblock,43,9 +ssandstonedhalfblock,43,9 +ssstonedhalfblock,43,9 +sssdhalfblock,43,9 +doublesmoothsandstoneslab,43,9 +doublessandstoneslab,43,9 +doublessstoneslab,43,9 +doublesssslab,43,9 +doublesmoothsandstonestep,43,9 +doublessandstonestep,43,9 +doublessstonestep,43,9 +doublesssstep,43,9 +doublesmoothsandstonehalfblock,43,9 +doublessandstonehalfblock,43,9 +doublessstonehalfblock,43,9 +doublessshalfblock,43,9 +dsmoothsandstoneslab,43,9 +dssandstoneslab,43,9 +dssstoneslab,43,9 +dsssslab,43,9 +dsmoothsandstonestep,43,9 +dssandstonestep,43,9 +dssstonestep,43,9 +dsssstep,43,9 +dsmoothsandstonehalfblock,43,9 +dssandstonehalfblock,43,9 +dssstonehalfblock,43,9 +dssshalfblock,43,9 +smoothstonestep,44,0 +stonestep,44,0 +sstep,44,0 +step,44,0 +smoothstoneslab,44,0 +stoneslab,44,0 +sslab,44,0 +slab,44,0 +smoothstonehalfblock,44,0 +stonehalfblock,44,0 +shalfblock,44,0 +halfblock,44,0 +sandstonestep,44,1 +sstonestep,44,1 +ssstep,44,1 +sandstoneslab,44,1 +sstoneslab,44,1 +ssslab,44,1 +sandstonehalfblock,44,1 +sstonehalfblock,44,1 +sshalfblock,44,1 +woodenstonestep,44,2 +woodstonestep,44,2 +wstonestep,44,2 +woodenstoneslab,44,2 +woodstoneslab,44,2 +wstoneslab,44,2 +woodenstonehalfblock,44,2 +woodstonehalfblock,44,2 +wstonehalfblock,44,2 +cobblestonestep,44,3 +cobblestep,44,3 +cstonestep,44,3 +csstep,44,3 +cobblestoneslab,44,3 +cobbleslab,44,3 +cstoneslab,44,3 +csslab,44,3 +cobblestonehalfblock,44,3 +cobblehalfblock,44,3 +cstonehalfblock,44,3 +cshalfblock,44,3 +brickstep,44,4 +bstep,44,4 +brickslab,44,4 +bslab,44,4 +brickhalfblock,44,4 +bhalfblock,44,4 +stonebrickstep,44,5 +stonebstep,44,5 +sbrickstep,44,5 +sbstep,44,5 +stonebrickslab,44,5 +stonebslab,44,5 +sbrickslab,44,5 +sbslab,44,5 +stonebrickhalfblock,44,5 +stonebhalfblock,44,5 +sbrickhalfblock,44,5 +sbhalfblock,44,5 +netherbrickslab,44,6 +hellbrickslab,44,6 +nbrickslab,44,6 +hbrickslab,44,6 +netherslab,44,6 +hellslab,44,6 +nbslab,44,6 +hbslab,44,6 +hslab,44,6 +nslab,44,6 +netherbrickstep,44,6 +hellbrickstep,44,6 +nbrickstep,44,6 +hbrickstep,44,6 +netherstep,44,6 +hellstep,44,6 +nbstep,44,6 +hbstep,44,6 +nstep,44,6 +hstep,44,6 +netherbrickhalfblock,44,6 +hellbrickhalfblock,44,6 +nbrickhalfblock,44,6 +hbrickhalfblock,44,6 +netherhalfblock,44,6 +hellhalfblock,44,6 +nbhalfblock,44,6 +hbhalfblock,44,6 +nhalfblock,44,6 +hhalfblock,44,6 +netherquartzstep,44,7 +hellquartzstep,44,7 +deathquartzstep,44,7 +nquartzstep,44,7 +hquartzstep,44,7 +dquartzstep,44,7 +quartzstep,44,7 +nqstep,44,7 +hqstep,44,7 +dqstep,44,7 +qstep,44,7 +netherquartzslab,44,7 +hellquartzslab,44,7 +deathquartzslab,44,7 +nquartzslab,44,7 +hquartzslab,44,7 +dquartzslab,44,7 +quartzslab,44,7 +nqslab,44,7 +hqslab,44,7 +dqslab,44,7 +qslab,44,7 +netherquartzhalfblock,44,7 +hellquartzhalfblock,44,7 +deathquartzhalfblock,44,7 +nquartzhalfblock,44,7 +hquartzhalfblock,44,7 +dquartzhalfblock,44,7 +quartzhalfblock,44,7 +nqhalfblock,44,7 +hqhalfblock,44,7 +dqhalfblock,44,7 +qhalfblock,44,7 +brickblock,45,0 +blockbrick,45,0 +bblock,45,0 +blockb,45,0 +tnt,46,0 +tntblock,46,0 +blocktnt,46,0 +bombblock,46,0 +blockbomb,46,0 +dynamiteblock,46,0 +blockdynamite,46,0 +bomb,46,0 +dynamite,46,0 +bookcase,47,0 +casebook,47,0 +bookshelf,47,0 +shelfbook,47,0 +bookblock,47,0 +blockbook,47,0 +mossycobblestone,48,0 +mosscobblestone,48,0 +mcobblestone,48,0 +mossycobble,48,0 +mosscobble,48,0 +mcobble,48,0 +mossstone,48,0 +mossystone,48,0 +mstone,48,0 +obsidian,49,0 +obsi,49,0 +obby,49,0 +torch,50,0 +burningstick,50,0 +burnstick,50,0 +fire,51,0 +flame,51,0 +flames,51,0 +mobspawner,52,0 +mobcage,52,0 +monsterspawner,52,0 +monstercage,52,0 +mspawner,52,0 +mcage,52,0 +spawner,52,0 +cage,52,0 +woodenstairs,53,0 +woodstairs,53,0 +wstairs,53,0 +woodenstair,53,0 +woodstair,53,0 +wstair,53,0 +chest,54,0 +container,54,0 +diamondore,56,0 +crystalore,56,0 +orediamond,56,0 +orecrystal,56,0 +dore,56,0 +ored,56,0 +diamondblock,57,0 +blockdiamond,57,0 +crystalblock,57,0 +blockcrystal,57,0 +dblock,57,0 +blockd,57,0 +workbench,58,0 +craftingbench,58,0 +crafterbench,58,0 +craftbench,58,0 +worktable,58,0 +craftingtable,58,0 +craftertable,58,0 +crafttable,58,0 +wbench,58,0 +cbench,58,0 +soil,60,0 +furnace,61,0 +litfurnace,62,0 +lfurnace,62,0 +burningfurnace,62,0 +burnfurnace,62,0 +bfurnace,62,0 +ladder,65,0 +minecarttrack,66,0 +minecartrails,66,0 +minecartrail,66,0 +mcarttrack,66,0 +mcartrails,66,0 +mcartrail,66,0 +mctrack,66,0 +mcrails,66,0 +mcrail,66,0 +track,66,0 +rails,66,0 +rail,66,0 +cobblestonestairs,67,0 +cstonestairs,67,0 +stonestairs,67,0 +cobblestairs,67,0 +csstairs,67,0 +sstairs,67,0 +cstairs,67,0 +cobblestonestair,67,0 +cstonestair,67,0 +stonestair,67,0 +cobblestair,67,0 +csstair,67,0 +sstair,67,0 +cstair,67,0 +lever,69,0 +stonepressureplate,70,0 +stonepressplate,70,0 +stonepplate,70,0 +stoneplate,70,0 +spressureplate,70,0 +spressplate,70,0 +spplate,70,0 +splate,70,0 +smoothstonepressureplate,70,0 +smoothstonepressplate,70,0 +smoothstonepplate,70,0 +smoothstoneplate,70,0 +sstonepressureplate,70,0 +sstonepressplate,70,0 +sstonepplate,70,0 +sstoneplate,70,0 +woodenpressureplate,72,0 +woodenpressplate,72,0 +woodenpplate,72,0 +woodenplate,72,0 +woodpressureplate,72,0 +woodpressplate,72,0 +woodpplate,72,0 +woodplate,72,0 +wpressureplate,72,0 +wpressplate,72,0 +wpplate,72,0 +wplate,72,0 +redstoneore,73,0 +redsore,73,0 +redore,73,0 +rstoneore,73,0 +rsore,73,0 +rore,73,0 +oreredstone,73,0 +orereds,73,0 +orered,73,0 +orerstone,73,0 +orers,73,0 +orer,73,0 +redstonetorch,76,0 +rstonetorch,76,0 +redstorch,76,0 +redtorch,76,0 +rstorch,76,0 +stonebutton,77,0 +smoothstonebutton,77,0 +sstonebutton,77,0 +sbutton,77,0 +button,77,0 +snowcover,78,0 +snowcovering,78,0 +scover,78,0 +ice,79,0 +frozenwater,79,0 +waterfrozen,79,0 +freezewater,79,0 +waterfreeze,79,0 +snowblock,80,0 +blocksnow,80,0 +sblock,80,0 +blocks,80,0 +cactus,81,0 +cactuses,81,0 +cacti,81,0 +clayblock,82,0 +blockclay,82,0 +cblock,82,0 +blockc,82,0 +jukebox,84,0 +jbox,84,0 +woodenfence,85,0 +fence,85,0 +woodfence,85,0 +wfence,85,0 +fencewooden,85,0 +fencewood,85,0 +fencew,85,0 +pumpkin,86,0 +netherrack,87,0 +netherrock,87,0 +netherstone,87,0 +hellrack,87,0 +hellrock,87,0 +hellstone,87,0 +deathrack,87,0 +deathrock,87,0 +deathstone,87,0 +nrack,87,0 +nrock,87,0 +nstone,87,0 +hrack,87,0 +hrock,87,0 +hstone,87,0 +drack,87,0 +drock,87,0 +dstone,87,0 +soulsand,88,0 +slowsand,88,0 +slowmud,88,0 +ssand,88,0 +smud,88,0 +mud,88,0 +glowstone,89,0 +glowingstoneblock,89,0 +lightstoneblock,89,0 +glowstoneblock,89,0 +blockglowingstone,89,0 +blocklightstone,89,0 +blockglowstone,89,0 +glowingstone,89,0 +lightstone,89,0 +glowingblock,89,0 +lightblock,89,0 +glowblock,89,0 +lstone,89,0 +gstone,89,0 +portal,90,0 +jackolantern,91,0 +pumpkinlantern,91,0 +glowingpumpkin,91,0 +lightpumpkin,91,0 +jpumpkin,91,0 +plantren,91,0 +glowpumpkin,91,0 +gpumpkin,91,0 +lpumpkin,91,0 +lockedchest,95,0 +lockchest,95,0 +jokechest,95,0 +whiteglass,95,0 +whitesglass,95,0 +whitestainedglass,95,0 +wglass,95,0 +wsglass,95,0 +wstainedglass,95,0 +sglass,95,0 +stainedglass,95,0 +orangeglass,95,1 +orangesglass,95,1 +orangestainedglass,95,1 +oglass,95,1 +osglass,95,1 +ostainedglass,95,1 +magentaglass,95,2 +magentasglass,95,2 +magentastainedglass,95,2 +mglass,95,2 +msglass,95,2 +mstainedglass,95,2 +lightblueglass,95,3 +lightbluesglass,95,3 +lightbluestainedglass,95,3 +lblueglass,95,3 +lbluesglass,95,3 +lbluestainedglass,95,3 +lightbluglass,95,3 +lightblusglass,95,3 +lightblustainedglass,95,3 +lbluglass,95,3 +lblusglass,95,3 +lblustainedglass,95,3 +lbglass,95,3 +lbsglass,95,3 +lbstainedglass,95,3 +yellowglass,95,4 +yellowsglass,95,4 +yellowstainedglass,95,4 +yglass,95,4 +ysglass,95,4 +ystainedglass,95,4 +lightgreenglass,95,5 +lightgreensglass,95,5 +lightgreenstainedglass,95,5 +lgreenglass,95,5 +lgreensglass,95,5 +lgreenstainedglass,95,5 +lightgreglass,95,5 +lightgresglass,95,5 +lightgrestainedglass,95,5 +lgreglass,95,5 +lgresglass,95,5 +lgrestainedglass,95,5 +limeglass,95,5 +limesglass,95,5 +limestainedglass,95,5 +lglass,95,5 +lsglass,95,5 +lstainedglass,95,5 +pinkglass,95,6 +pinksglass,95,6 +pinkstainedglass,95,6 +piglass,95,6 +pisglass,95,6 +pistainedglass,95,6 +darkgrayglass,95,7 +darkgraysglass,95,7 +darkgraystainedglass,95,7 +dgrayglass,95,7 +dgraysglass,95,7 +dgraystainedglass,95,7 +darkgreyglass,95,7 +darkgreysglass,95,7 +darkgreystainedglass,95,7 +dgreyglass,95,7 +dgreysglass,95,7 +dgreystainedglass,95,7 +darkgraglass,95,7 +darkgrasglass,95,7 +darkgrastainedglass,95,7 +dgraglass,95,7 +dgrasglass,95,7 +dgrastainedglass,95,7 +grayglass,95,7 +graysglass,95,7 +graystainedglass,95,7 +greyglass,95,7 +greysglass,95,7 +greystainedglass,95,7 +graglass,95,7 +grasglass,95,7 +grastainedglass,95,7 +lightgrayglass,95,8 +lightgraysglass,95,8 +lightgraystainedglass,95,8 +lgrayglass,95,8 +lgraysglass,95,8 +lgraystainedglass,95,8 +lightgreyglass,95,8 +lightgreysglass,95,8 +lightgreystainedglass,95,8 +lgreyglass,95,8 +lgreysglass,95,8 +lgreystainedglass,95,8 +lightgraglass,95,8 +lightgrasglass,95,8 +lightgrastainedglass,95,8 +lgraglass,95,8 +lgrasglass,95,8 +lgrastainedglass,95,8 +silverglass,95,8 +silversglass,95,8 +silverstainedglass,95,8 +siglass,95,8 +siasglass,95,8 +siastainedglass,95,8 +cyanglass,95,9 +cyansglass,95,9 +cyanstainedglass,95,9 +cglass,95,9 +csglass,95,9 +cstainedglass,95,9 +purpleglass,95,10 +purplesglass,95,10 +purplestainedglass,95,10 +puglass,95,10 +pusglass,95,10 +pustainedglass,95,10 +blueglass,95,11 +bluesglass,95,11 +bluestainedglass,95,11 +bluglass,95,11 +blusglass,95,11 +blustainedglass,95,11 +brownglass,95,12 +brownsglass,95,12 +brownstainedglass,95,12 +broglass,95,12 +brosglass,95,12 +brostainedglass,95,12 +darkgreenglass,95,13 +darkgreensglass,95,13 +darkgreenstainedglass,95,13 +dgreenglass,95,13 +dgreensglass,95,13 +dgreenstainedglass,95,13 +greenglass,95,13 +greensglass,95,13 +greenstainedglass,95,13 +darkgreglass,95,13 +darkgresglass,95,13 +darkgrestainedglass,95,13 +dgreglass,95,13 +dgresglass,95,13 +dgrestainedglass,95,13 +greglass,95,13 +gresglass,95,13 +grestainedglass,95,13 +redglass,95,14 +redsglass,95,14 +redstainedglass,95,14 +rglass,95,14 +rsglass,95,14 +rstainedglass,95,14 +blackglass,95,15 +blacksglass,95,15 +blackstainedglass,95,15 +blaglass,95,15 +blasglass,95,15 +blastainedglass,95,15 +trapdoor,96,0 +doortrap,96,0 +hatch,96,0 +tdoor,96,0 +doort,96,0 +trapd,96,0 +dtrap,96,0 +silverfish,97,0 +silverfishsmoothstone,97,0 +silverfishsstone,97,0 +sfishsmoothstone,97,0 +sfishsstone,97,0 +fishsmoothstone,97,0 +fishsstone,97,0 +sfsmoothstone,97,0 +sfsstone,97,0 +trapsmoothstone,97,0 +trapsstone,97,0 +monsteregg,97,0 +monstereggsmoothstone,97,0 +monstereggsstone,97,0 +meggsmoothstone,97,0 +meggsstone,97,0 +mesmoothstone,97,0 +messtone,97,0 +silverfishcobblestone,97,1 +silverfishcstone,97,1 +sfishcobblestone,97,1 +sfishcstone,97,1 +fishcobblestone,97,1 +fishcstone,97,1 +sfcobblestone,97,1 +sfcstone,97,1 +trapcobblestone,97,1 +trapcstone,97,1 +monstereggcobblestone,97,1 +monstereggcstone,97,1 +meggcobblestone,97,1 +meggcstone,97,1 +mecobblestone,97,1 +mecstone,97,1 +silverfishstonebrick,97,2 +silverfishsbrick,97,2 +sfishstonebrick,97,2 +sfishsbrick,97,2 +fishstonebrick,97,2 +fishsbrick,97,2 +sfstonebrick,97,2 +sfsbrick,97,2 +trapstonebrick,97,2 +trapsbrick,97,2 +monstereggstonebrick,97,2 +monstereggsbrick,97,2 +meggstonebrick,97,2 +meggsbrick,97,2 +mestonebrick,97,2 +mesbrick,97,2 +silverfishmossystonebrick,97,3 +silverfishmossstonebrick,97,3 +silverfishmstonebrick,97,3 +silverfishmsbrick,97,3 +sfishmossystonebrick,97,3 +sfishmossstonebrick,97,3 +sfishmstonebrick,97,3 +sfishmsbrick,97,3 +fishmossystonebrick,97,3 +fishmossstonebrick,97,3 +fishmstonebrick,97,3 +fishmsbrick,97,3 +sfmossystonebrick,97,3 +sfmossstonebrick,97,3 +sfmstonebrick,97,3 +sfmsbrick,97,3 +trapmossystonebrick,97,3 +trapmossstonebrick,97,3 +trapmstonebrick,97,3 +trapmsbrick,97,3 +monstereggmossystonebrick,97,3 +monstereggmossstonebrick,97,3 +monstereggmstonebrick,97,3 +monstereggmsbrick,97,3 +meggmossystonebrick,97,3 +meggmossstonebrick,97,3 +meggmstonebrick,97,3 +meggmsbrick,97,3 +memossystonebrick,97,3 +memossstonebrick,97,3 +memstonebrick,97,3 +memsbrick,97,3 +silverfishcrackedstonebrick,97,4 +silverfishcrackstonebrick,97,4 +silverfishcrstonebrick,97,4 +silverfishcrsbrick,97,4 +sfishcrackedstonebrick,97,4 +sfishcrackstonebrick,97,4 +sfishcrstonebrick,97,4 +sfishcrsbrick,97,4 +fishcrackedstonebrick,97,4 +fishcrackstonebrick,97,4 +fishcrstonebrick,97,4 +fishcrsbrick,97,4 +sfcrackedstonebrick,97,4 +sfcrackstonebrick,97,4 +sfcrstonebrick,97,4 +sfcrsbrick,97,4 +trapcrackedstonebrick,97,4 +trapcrackstonebrick,97,4 +trapcrstonebrick,97,4 +trapcrsbrick,97,4 +monstereggcrackedstonebrick,97,4 +monstereggcrackstonebrick,97,4 +monstereggcrstonebrick,97,4 +monstereggcrsbrick,97,4 +meggcrackedstonebrick,97,4 +meggcrackstonebrick,97,4 +meggcrstonebrick,97,4 +meggcrsbrick,97,4 +mecrackedstonebrick,97,4 +mecrackstonebrick,97,4 +mecrstonebrick,97,4 +mecrsbrick,97,4 +silverfishcirclestonebrick,97,5 +silverfishcistonebrick,97,5 +silverfishcisbrick,97,5 +sfishcirclestonebrick,97,5 +sfishcistonebrick,97,5 +sfishcisbrick,97,5 +fishcirclestonebrick,97,5 +fishcistonebrick,97,5 +fishcisbrick,97,5 +sfcirclestonebrick,97,5 +sfcistonebrick,97,5 +sfcisbrick,97,5 +trapcirclestonebrick,97,5 +trapcistonebrick,97,5 +trapcisbrick,97,5 +monstereggcirclestonebrick,97,5 +monstereggcistonebrick,97,5 +monstereggcisbrick,97,5 +meggcirclestonebrick,97,5 +meggcistonebrick,97,5 +meggcisbrick,97,5 +mecirclestonebrick,97,5 +mecistonebrick,97,5 +mecisbrick,97,5 +stonebrick,98,0 +stonebricks,98,0 +stonebrickblock,98,0 +stonebb,98,0 +sbrick,98,0 +mossystonebrick,98,1 +mossystonebricks,98,1 +mossystonebrickblock,98,1 +mossystonebb,98,1 +mossstonebrick,98,1 +mossstonebricks,98,1 +mossstonebrickblock,98,1 +mossstonebb,98,1 +mstonebrick,98,1 +mstonebricks,98,1 +mstonebrickblock,98,1 +mstonebb,98,1 +mosssbrick,98,1 +mosssbricks,98,1 +mosssbrickblock,98,1 +mosssbb,98,1 +msbrick,98,1 +msbricks,98,1 +msbrickblock,98,1 +crackedstone,98,2 +crackedstonebrick,98,2 +crackedstonebricks,98,2 +crackedstonebrickblock,98,2 +crackedstonebb,98,2 +crackstonebrick,98,2 +crackstonebricks,98,2 +crackstonebrickblock,98,2 +crackstonebb,98,2 +crstonebrick,98,2 +crstonebricks,98,2 +crstonebrickblock,98,2 +crstonebb,98,2 +cracksbrick,98,2 +cracksbricks,98,2 +cracksbrickblock,98,2 +cracksbb,98,2 +crsbrick,98,2 +crsbricks,98,2 +crsbrickblock,98,2 +circlestone,98,3 +circlestonebrick,98,3 +circlestonebricks,98,3 +circlestonebrickblock,98,3 +circlestonebb,98,3 +cistonebrick,98,3 +cistonebricks,98,3 +cistonebrickblock,98,3 +cistonebb,98,3 +circlesbrick,98,3 +circlesbricks,98,3 +circlesbrickblock,98,3 +circlesbb,98,3 +cisbrick,98,3 +cisbricks,98,3 +cisbrickblock,98,3 +giantredmushroom,99,0 +hugeredmushroom,99,0 +bigredmushroom,99,0 +gredmushroom,99,0 +hredmushroom,99,0 +bredmushroom,99,0 +giantrmushroom,99,0 +hugermushroom,99,0 +bigrmushroom,99,0 +grmushroom,99,0 +hrmushroom,99,0 +brmushroom,99,0 +giantredmush,99,0 +hugeredmush,99,0 +bigredmush,99,0 +gredmush,99,0 +hredmush,99,0 +bredmush,99,0 +giantrmush,99,0 +hugermush,99,0 +bigrmush,99,0 +grmush,99,0 +hrmush,99,0 +brmush,99,0 +giantbrownmushroom,100,0 +hugebrownmushroom,100,0 +bigbrownmushroom,100,0 +gbrownmushroom,100,0 +hbrownmushroom,100,0 +bbrownmushroom,100,0 +giantbmushroom,100,0 +hugebmushroom,100,0 +bigbmushroom,100,0 +gbmushroom,100,0 +hbmushroom,100,0 +bbmushroom,100,0 +giantbrownmush,100,0 +hugebrownmush,100,0 +bigbrownmush,100,0 +gbrownmush,100,0 +hbrownmush,100,0 +bbrownmush,100,0 +giantbmush,100,0 +hugebmush,100,0 +bigbmush,100,0 +gbmush,100,0 +hbmush,100,0 +bbmush,100,0 +ironbars,101,0 +ironbarsb,101,0 +ironbarsblock,101,0 +ironfence,101,0 +metalbars,101,0 +metalbarsb,101,0 +metalbarsblock,101,0 +metalfence,101,0 +jailbars,101,0 +jailbarsb,101,0 +jailbarsblock,101,0 +jailfence,101,0 +mbars,101,0 +mbarsb,101,0 +mbarsblock,101,0 +mfence,101,0 +jbars,101,0 +jbarsb,101,0 +jbarsblock,101,0 +jfence,101,0 +ibars,101,0 +ibarsb,101,0 +ibarsblock,101,0 +ifence,101,0 +glasspane,102,0 +glassp,102,0 +paneglass,102,0 +pglass,102,0 +flatglass,102,0 +fglass,102,0 +skinnyglass,102,0 +glassflat,102,0 +glassf,102,0 +glassskinny,102,0 +glasss,102,0 +melon,103,0 +watermelon,103,0 +greenmelon,103,0 +melongreen,103,0 +melonblock,103,0 +watermelonblock,103,0 +greenmelonblock,103,0 +vines,106,0 +vine,106,0 +greenvines,106,0 +greenvine,106,0 +gardenvines,106,0 +gardenvine,106,0 +vinesgreen,106,0 +vinegreen,106,0 +vinesgarden,106,0 +vinegarden,106,0 +vinesg,106,0 +vineg,106,0 +gvines,106,0 +gvine,106,0 +woodgate,107,0 +woodenfencegate,107,0 +wfencegate,107,0 +woodfencegate,107,0 +woodengate,107,0 +wgate,107,0 +gate,107,0 +gardengate,107,0 +ggate,107,0 +fencegate,107,0 +fgate,107,0 +brickstairs,108,0 +redbrickstairs,108,0 +redbstairs,108,0 +rbrickstairs,108,0 +bstairs,108,0 +redstairs,108,0 +brickstair,108,0 +redbrickstair,108,0 +redbstair,108,0 +rbrickstair,108,0 +bstair,108,0 +redstair,108,0 +stonebrickstairs,109,0 +stonebstairs,109,0 +sbstairs,109,0 +cementbrickstairs,109,0 +cementstairs,109,0 +cementbstairs,109,0 +cbstairs,109,0 +greybrickstairs,109,0 +greybstairs,109,0 +greystairs,109,0 +mycelium,110,0 +purplegrass,110,0 +pinkgrass,110,0 +mycel,110,0 +swampgrass,110,0 +sgrass,110,0 +mushroomgrass,110,0 +mushgrass,110,0 +lilypad,111,0 +waterlily,111,0 +lily,111,0 +swamppad,111,0 +lpad,111,0 +wlily,111,0 +netherbrickblock,112,0 +hellbrickblock,112,0 +deathbrickblock,112,0 +nbrickblock,112,0 +hbrickblock,112,0 +dbrickblock,112,0 +netherbblock,112,0 +hellbblock,112,0 +deathbblock,112,0 +nbblock,112,0 +hbblock,112,0 +dbblock,112,0 +netherbrickfence,113,0 +hellbrickfence,113,0 +nbrickfence,113,0 +hbrickfence,113,0 +netherbfence,113,0 +hellbfence,113,0 +netherfence,113,0 +hellfence,113,0 +nbfence,113,0 +hbfence,113,0 +nfence,113,0 +hfence,113,0 +netherbrickstairs,114,0 +hellbrickstairs,114,0 +nbrickstairs,114,0 +hbrickstairs,114,0 +netherbstairs,114,0 +hellbstairs,114,0 +netherstairs,114,0 +hellstairs,114,0 +nbstairs,114,0 +hbstairs,114,0 +nstairs,114,0 +hstairs,114,0 +netherbrickstair,114,0 +hellbrickstair,114,0 +nbrickstair,114,0 +hbrickstair,114,0 +netherbstair,114,0 +hellbstair,114,0 +netherstair,114,0 +hellstair,114,0 +nbstair,114,0 +hbstair,114,0 +nstair,114,0 +hstair,114,0 +enchantmenttable,116,0 +enchantingtable,116,0 +enchanttable,116,0 +etable,116,0 +magicaltable,116,0 +magictable,116,0 +mtable,116,0 +enchantmentdesk,116,0 +enchantingdesk,116,0 +enchantdesk,116,0 +edesk,116,0 +magicaldesk,116,0 +magicdesk,116,0 +mdesk,116,0 +booktable,116,0 +bookdesk,116,0 +btable,116,0 +bdesk,116,0 +enderportal,119,0 +endergoo,119,0 +endgoo,119,0 +endportal,119,0 +egoo,119,0 +eportal,119,0 +enderportalframe,120,0 +endportalframe,120,0 +endgooframe,120,0 +endergooframe,120,0 +egooframe,120,0 +eportalframe,120,0 +enderframe,120,0 +endframe,120,0 +enderstone,121,0 +endstone,121,0 +endrock,121,0 +enderrock,121,0 +erock,121,0 +estone,121,0 +enderdragonegg,122,0 +endegg,122,0 +dragonegg,122,0 +degg,122,0 +bossegg,122,0 +begg,122,0 +redstonelamp,123,0 +redlamp,123,0 +rslamp,123,0 +woodendoublestep,125,0 +woodendstep,125,0 +wooddoublestep,125,0 +wooddstep,125,0 +wdoublestep,125,0 +wdstep,125,0 +doublewoodenstep,125,0 +dwoodenstep,125,0 +doublewoodstep,125,0 +dwoodstep,125,0 +doublewstep,125,0 +dwstep,125,0 +woodendoubleslab,125,0 +woodendslab,125,0 +wooddoubleslab,125,0 +wooddslab,125,0 +wdoubleslab,125,0 +wdslab,125,0 +doublewoodenslab,125,0 +dwoodenslab,125,0 +doublewoodslab,125,0 +dwoodslab,125,0 +doublewslab,125,0 +dwslab,125,0 +woodendoublehalfblock,125,0 +woodendhalfblock,125,0 +wooddoublehalfblock,125,0 +wooddhalfblock,125,0 +wdoublehalfblock,125,0 +wdhalfblock,125,0 +doublewoodenhalfblock,125,0 +dwoodenhalfblock,125,0 +doublewoodhalfblock,125,0 +dwoodhalfblock,125,0 +doublewhalfblock,125,0 +dwhalfblock,125,0 +oakwoodendoublehalfblock,125,0 +oakwoodendhalfblock,125,0 +oakwooddoublehalfblock,125,0 +oakwooddhalfblock,125,0 +oakwdoublehalfblock,125,0 +oakwdhalfblock,125,0 +oakdoublewoodenhalfblock,125,0 +oakdwoodenhalfblock,125,0 +oakdoublewoodhalfblock,125,0 +oakdwoodhalfblock,125,0 +oakdoublewhalfblock,125,0 +oakdwhalfblock,125,0 +oakdoublehalfblock,125,0 +oakdhalfblock,125,0 +odhalfblock,125,0 +oakwoodendoublestep,125,0 +oakwoodendstep,125,0 +oakwooddoublestep,125,0 +oakwooddstep,125,0 +oakwdoublestep,125,0 +oakwdstep,125,0 +oakdoublewoodenstep,125,0 +oakdwoodenstep,125,0 +oakdoublewoodstep,125,0 +oakdwoodstep,125,0 +oakdoublewstep,125,0 +oakdwstep,125,0 +oakdoublestep,125,0 +oakdstep,125,0 +odstep,125,0 +oakwoodendoubleslab,125,0 +oakwoodendslab,125,0 +oakwooddoubleslab,125,0 +oakwooddslab,125,0 +oakwdoubleslab,125,0 +oakwdslab,125,0 +oakdoublewoodenslab,125,0 +oakdwoodenslab,125,0 +oakdoublewoodslab,125,0 +oakdwoodslab,125,0 +oakdoublewslab,125,0 +oakdwslab,125,0 +oakdoubleslab,125,0 +oakdslab,125,0 +odslab,125,0 +sprucewoodendoublestep,125,1 +sprucewoodendstep,125,1 +sprucewooddoublestep,125,1 +sprucewooddstep,125,1 +sprucewdoublestep,125,1 +sprucewdstep,125,1 +sprucedoublewoodenstep,125,1 +sprucedwoodenstep,125,1 +sprucedoublewoodstep,125,1 +sprucedwoodstep,125,1 +sprucedoublewstep,125,1 +sprucedwstep,125,1 +sprucedoublestep,125,1 +sprucedstep,125,1 +sprucewoodendoubleslab,125,1 +sprucewoodendslab,125,1 +sprucewooddoubleslab,125,1 +sprucewooddslab,125,1 +sprucewdoubleslab,125,1 +sprucewdslab,125,1 +sprucedoublewoodenslab,125,1 +sprucedwoodenslab,125,1 +sprucedoublewoodslab,125,1 +sprucedwoodslab,125,1 +sprucedoublewslab,125,1 +sprucedwslab,125,1 +sprucedoubleslab,125,1 +sprucedslab,125,1 +sprucewoodendoublehalfblock,125,1 +sprucewoodendhalfblock,125,1 +sprucewooddoublehalfblock,125,1 +sprucewooddhalfblock,125,1 +sprucewdoublehalfblock,125,1 +sprucewdhalfblock,125,1 +sprucedoublewoodenhalfblock,125,1 +sprucedwoodenhalfblock,125,1 +sprucedoublewoodhalfblock,125,1 +sprucedwoodhalfblock,125,1 +sprucedoublewhalfblock,125,1 +sprucedwhalfblock,125,1 +sprucedoublehalfblock,125,1 +sprucedhalfblock,125,1 +darkwoodendoublestep,125,1 +darkwoodendstep,125,1 +darkwooddoublestep,125,1 +darkwooddstep,125,1 +darkwdoublestep,125,1 +darkwdstep,125,1 +darkdoublewoodenstep,125,1 +darkdwoodenstep,125,1 +darkdoublewoodstep,125,1 +darkdwoodstep,125,1 +darkdoublewstep,125,1 +darkdwstep,125,1 +darkdoublestep,125,1 +darkdstep,125,1 +ddstep,125,1 +darkwoodendoubleslab,125,1 +darkwoodendslab,125,1 +darkwooddoubleslab,125,1 +darkwooddslab,125,1 +darkwdoubleslab,125,1 +darkwdslab,125,1 +darkdoublewoodenslab,125,1 +darkdwoodenslab,125,1 +darkdoublewoodslab,125,1 +darkdwoodslab,125,1 +darkdoublewslab,125,1 +darkdwslab,125,1 +darkdoubleslab,125,1 +darkdslab,125,1 +ddslab,125,1 +darkwoodendoublehalfblock,125,1 +darkwoodendhalfblock,125,1 +darkwooddoublehalfblock,125,1 +darkwooddhalfblock,125,1 +darkwdoublehalfblock,125,1 +darkwdhalfblock,125,1 +darkdoublewoodenhalfblock,125,1 +darkdwoodenhalfblock,125,1 +darkdoublewoodhalfblock,125,1 +darkdwoodhalfblock,125,1 +darkdoublewhalfblock,125,1 +darkdwhalfblock,125,1 +darkdoublehalfblock,125,1 +darkdhalfblock,125,1 +ddhalfblock,125,1 +birchwoodendoublestep,125,2 +birchwoodendstep,125,2 +birchwooddoublestep,125,2 +birchwooddstep,125,2 +birchwdoublestep,125,2 +birchwdstep,125,2 +birchdoublewoodenstep,125,2 +birchdwoodenstep,125,2 +birchdoublewoodstep,125,2 +birchdwoodstep,125,2 +birchdoublewstep,125,2 +birchdwstep,125,2 +birchdoublestep,125,2 +birchdstep,125,2 +birchwoodendoubleslab,125,2 +birchwoodendslab,125,2 +birchwooddoubleslab,125,2 +birchwooddslab,125,2 +birchwdoubleslab,125,2 +birchwdslab,125,2 +birchdoublewoodenslab,125,2 +birchdwoodenslab,125,2 +birchdoublewoodslab,125,2 +birchdwoodslab,125,2 +birchdoublewslab,125,2 +birchdwslab,125,2 +birchdoubleslab,125,2 +birchdslab,125,2 +birchwoodendoublehalfblock,125,2 +birchwoodendhalfblock,125,2 +birchwooddoublehalfblock,125,2 +birchwooddhalfblock,125,2 +birchwdoublehalfblock,125,2 +birchwdhalfblock,125,2 +birchdoublewoodenhalfblock,125,2 +birchdwoodenhalfblock,125,2 +birchdoublewoodhalfblock,125,2 +birchdwoodhalfblock,125,2 +birchdoublewhalfblock,125,2 +birchdwhalfblock,125,2 +birchdoublehalfblock,125,2 +birchdhalfblock,125,2 +lightwoodendoublehalfblock,125,2 +lightwoodendhalfblock,125,2 +lightwooddoublehalfblock,125,2 +lightwooddhalfblock,125,2 +lightwdoublehalfblock,125,2 +lightwdhalfblock,125,2 +lightdoublewoodenhalfblock,125,2 +lightdwoodenhalfblock,125,2 +lightdoublewoodhalfblock,125,2 +lightdwoodhalfblock,125,2 +lightdoublewhalfblock,125,2 +lightdwhalfblock,125,2 +lightdoublehalfblock,125,2 +lightdhalfblock,125,2 +ldhalfblock,125,2 +lightwoodendoublestep,125,2 +lightwoodendstep,125,2 +lightwooddoublestep,125,2 +lightwooddstep,125,2 +lightwdoublestep,125,2 +lightwdstep,125,2 +lightdoublewoodenstep,125,2 +lightdwoodenstep,125,2 +lightdoublewoodstep,125,2 +lightdwoodstep,125,2 +lightdoublewstep,125,2 +lightdwstep,125,2 +lightdoublestep,125,2 +lightdstep,125,2 +ldstep,125,2 +lightwoodendoubleslab,125,2 +lightwoodendslab,125,2 +lightwooddoubleslab,125,2 +lightwooddslab,125,2 +lightwdoubleslab,125,2 +lightwdslab,125,2 +lightdoublewoodenslab,125,2 +lightdwoodenslab,125,2 +lightdoublewoodslab,125,2 +lightdwoodslab,125,2 +lightdoublewslab,125,2 +lightdwslab,125,2 +lightdoubleslab,125,2 +lightdslab,125,2 +ldslab,125,2 +junglewoodendoublestep,125,3 +junglewoodendstep,125,3 +junglewooddoublestep,125,3 +junglewooddstep,125,3 +junglewdoublestep,125,3 +junglewdstep,125,3 +jungledoublewoodenstep,125,3 +jungledwoodenstep,125,3 +jungledoublewoodstep,125,3 +jungledwoodstep,125,3 +jungledoublewstep,125,3 +jungledwstep,125,3 +jungledoublestep,125,3 +jungledstep,125,3 +jdstep,125,3 +junglewoodendoubleslab,125,3 +junglewoodendslab,125,3 +junglewooddoubleslab,125,3 +junglewooddslab,125,3 +junglewdoubleslab,125,3 +junglewdslab,125,3 +jungledoublewoodenslab,125,3 +jungledwoodenslab,125,3 +jungledoublewoodslab,125,3 +jungledwoodslab,125,3 +jungledoublewslab,125,3 +jungledwslab,125,3 +jungledoubleslab,125,3 +jungledslab,125,3 +jdslab,125,3 +junglewoodendoublehalfblock,125,3 +junglewoodendhalfblock,125,3 +junglewooddoublehalfblock,125,3 +junglewooddhalfblock,125,3 +junglewdoublehalfblock,125,3 +junglewdhalfblock,125,3 +jungledoublewoodenhalfblock,125,3 +jungledwoodenhalfblock,125,3 +jungledoublewoodhalfblock,125,3 +jungledwoodhalfblock,125,3 +jungledoublewhalfblock,125,3 +jungledwhalfblock,125,3 +jungledoublehalfblock,125,3 +jungledhalfblock,125,3 +jdhalfblock,125,3 +forestwoodendoublehalfblock,125,3 +forestwoodendhalfblock,125,3 +forestwooddoublehalfblock,125,3 +forestwooddhalfblock,125,3 +forestwdoublehalfblock,125,3 +forestwdhalfblock,125,3 +forestdoublewoodenhalfblock,125,3 +forestdwoodenhalfblock,125,3 +forestdoublewoodhalfblock,125,3 +forestdwoodhalfblock,125,3 +forestdoublewhalfblock,125,3 +forestdwhalfblock,125,3 +forestdoublehalfblock,125,3 +forestdhalfblock,125,3 +fdhalfblock,125,3 +forestwoodendoublestep,125,3 +forestwoodendstep,125,3 +forestwooddoublestep,125,3 +forestwooddstep,125,3 +forestwdoublestep,125,3 +forestwdstep,125,3 +forestdoublewoodenstep,125,3 +forestdwoodenstep,125,3 +forestdoublewoodstep,125,3 +forestdwoodstep,125,3 +forestdoublewstep,125,3 +forestdwstep,125,3 +forestdoublestep,125,3 +forestdstep,125,3 +fdstep,125,3 +forestwoodendoubleslab,125,3 +forestwoodendslab,125,3 +forestwooddoubleslab,125,3 +forestwooddslab,125,3 +forestwdoubleslab,125,3 +forestwdslab,125,3 +forestdoublewoodenslab,125,3 +forestdwoodenslab,125,3 +forestdoublewoodslab,125,3 +forestdwoodslab,125,3 +forestdoublewslab,125,3 +forestdwslab,125,3 +forestdoubleslab,125,3 +forestdslab,125,3 +fdslab,125,3 +acaciawoodendoublestep,125,4 +acaciawoodendstep,125,4 +acaciawooddoublestep,125,4 +acaciawooddstep,125,4 +acaciawdoublestep,125,4 +acaciawdstep,125,4 +acaciadoublewoodenstep,125,4 +acaciadwoodenstep,125,4 +acaciadoublewoodstep,125,4 +acaciadwoodstep,125,4 +acaciadoublewstep,125,4 +acaciadwstep,125,4 +acaciadoublestep,125,4 +acaciadstep,125,4 +adstep,125,4 +acaciawoodendoubleslab,125,4 +acaciawoodendslab,125,4 +acaciawooddoubleslab,125,4 +acaciawooddslab,125,4 +acaciawdoubleslab,125,4 +acaciawdslab,125,4 +acaciadoublewoodenslab,125,4 +acaciadwoodenslab,125,4 +acaciadoublewoodslab,125,4 +acaciadwoodslab,125,4 +acaciadoublewslab,125,4 +acaciadwslab,125,4 +acaciadoubleslab,125,4 +acaciadslab,125,4 +adslab,125,4 +acaciawoodendoublehalfblock,125,4 +acaciawoodendhalfblock,125,4 +acaciawooddoublehalfblock,125,4 +acaciawooddhalfblock,125,4 +acaciawdoublehalfblock,125,4 +acaciawdhalfblock,125,4 +acaciadoublewoodenhalfblock,125,4 +acaciadwoodenhalfblock,125,4 +acaciadoublewoodhalfblock,125,4 +acaciadwoodhalfblock,125,4 +acaciadoublewhalfblock,125,4 +acaciadwhalfblock,125,4 +acaciadoublehalfblock,125,4 +acaciadhalfblock,125,4 +adhalfblock,125,4 +darkoakwoodendoublehalfblock,125,5 +darkoakwoodendhalfblock,125,5 +darkoakwooddoublehalfblock,125,5 +darkoakwooddhalfblock,125,5 +darkoakwdoublehalfblock,125,5 +darkoakwdhalfblock,125,5 +darkoakdoublewoodenhalfblock,125,5 +darkoakdwoodenhalfblock,125,5 +darkoakdoublewoodhalfblock,125,5 +darkoakdwoodhalfblock,125,5 +darkoakdoublewhalfblock,125,5 +darkoakdwhalfblock,125,5 +darkoakdoublehalfblock,125,5 +darkoakdhalfblock,125,5 +dodhalfblock,125,5 +darkoakwoodendoublestep,125,5 +darkoakwoodendstep,125,5 +darkoakwooddoublestep,125,5 +darkoakwooddstep,125,5 +darkoakwdoublestep,125,5 +darkoakwdstep,125,5 +darkoakdoublewoodenstep,125,5 +darkoakdwoodenstep,125,5 +darkoakdoublewoodstep,125,5 +darkoakdwoodstep,125,5 +darkoakdoublewstep,125,5 +darkoakdwstep,125,5 +darkoakdoublestep,125,5 +darkoakdstep,125,5 +dodstep,125,5 +darkoakwoodendoubleslab,125,5 +darkoakwoodendslab,125,5 +darkoakwooddoubleslab,125,5 +darkoakwooddslab,125,5 +darkoakwdoubleslab,125,5 +darkoakwdslab,125,5 +darkoakdoublewoodenslab,125,5 +darkoakdwoodenslab,125,5 +darkoakdoublewoodslab,125,5 +darkoakdwoodslab,125,5 +darkoakdoublewslab,125,5 +darkoakdwslab,125,5 +darkoakdoubleslab,125,5 +darkoakdslab,125,5 +dodslab,125,5 +woodenstep,126,0 +woodstep,126,0 +wstep,126,0 +woodenslab,126,0 +woodslab,126,0 +wslab,126,0 +woodenhalfblock,126,0 +woodhalfblock,126,0 +whalfblock,126,0 +oakwoodenstep,126,0 +oakwoodstep,126,0 +oakwstep,126,0 +oakstep,126,0 +ostep,126,0 +oakwoodenslab,126,0 +oakwoodslab,126,0 +oakwslab,126,0 +oakslab,126,0 +oslab,126,0 +oakwoodenhalfblock,126,0 +oakwoodhalfblock,126,0 +oakwhalfblock,126,0 +oakhalfblock,126,0 +ohalfblock,126,0 +sprucewoodenstep,126,1 +sprucewoodstep,126,1 +sprucewstep,126,1 +sprucestep,126,1 +sprucewoodenslab,126,1 +sprucewoodslab,126,1 +sprucewslab,126,1 +spruceslab,126,1 +sprucewoodenhalfblock,126,1 +sprucewoodhalfblock,126,1 +sprucewhalfblock,126,1 +sprucehalfblock,126,1 +darkwoodenstep,126,1 +darkwoodstep,126,1 +darkwstep,126,1 +darkstep,126,1 +darkwoodenslab,126,1 +darkwoodslab,126,1 +darkwslab,126,1 +darkslab,126,1 +darkwoodenhalfblock,126,1 +darkwoodhalfblock,126,1 +darkwhalfblock,126,1 +darkhalfblock,126,1 +birchwoodenstep,126,2 +birchwoodstep,126,2 +birchwstep,126,2 +birchstep,126,2 +birchwoodenslab,126,2 +birchwoodslab,126,2 +birchwslab,126,2 +birchslab,126,2 +birchwoodenhalfblock,126,2 +birchwoodhalfblock,126,2 +birchwhalfblock,126,2 +birchhalfblock,126,2 +lightwoodenstep,126,2 +lightwoodstep,126,2 +lightwstep,126,2 +lightstep,126,2 +lstep,126,2 +lightwoodenslab,126,2 +lightwoodslab,126,2 +lightwslab,126,2 +lightslab,126,2 +lslab,126,2 +lightwoodenhalfblock,126,2 +lightwoodhalfblock,126,2 +lightwhalfblock,126,2 +lighthalfblock,126,2 +lhalfblock,126,2 +junglewoodenstep,126,3 +junglewoodstep,126,3 +junglewstep,126,3 +junglestep,126,3 +jstep,126,3 +junglewoodenslab,126,3 +junglewoodslab,126,3 +junglewslab,126,3 +jungleslab,126,3 +jslab,126,3 +junglewoodenhalfblock,126,3 +junglewoodhalfblock,126,3 +junglewhalfblock,126,3 +junglehalfblock,126,3 +jhalfblock,126,3 +forestwoodenstep,126,3 +forestwoodstep,126,3 +forestwstep,126,3 +foreststep,126,3 +fstep,126,3 +forestwoodenslab,126,3 +forestwoodslab,126,3 +forestwslab,126,3 +forestslab,126,3 +fslab,126,3 +forestwoodenhalfblock,126,3 +forestwoodhalfblock,126,3 +forestwhalfblock,126,3 +foresthalfblock,126,3 +fhalfblock,126,3 +acaciawoodenstep,126,4 +acaciawoodstep,126,4 +acaciawstep,126,4 +acaciastep,126,4 +astep,126,4 +acaciawoodenslab,126,4 +acaciawoodslab,126,4 +acaciawslab,126,4 +acaciaslab,126,4 +aslab,126,4 +acaciawoodenhalfblock,126,4 +acaciawoodhalfblock,126,4 +acaciawhalfblock,126,4 +acaciahalfblock,126,4 +ahalfblock,126,4 +darkoakwoodenstep,126,5 +darkoakwoodstep,126,5 +darkoakwstep,126,5 +darkoakstep,126,5 +dostep,126,5 +darkoakwoodenslab,126,5 +darkoakwoodslab,126,5 +darkoakwslab,126,5 +darkoakslab,126,5 +doslab,126,5 +darkoakwoodenhalfblock,126,5 +darkoakwoodhalfblock,126,5 +darkoakwhalfblock,126,5 +darkoakhalfblock,126,5 +dohalfblock,126,5 +cocoaplant,127,0 +cocoplant,127,0 +cplant,127,0 +cocoafruit,127,0 +cocofruit,127,0 +cfruit,127,0 +cocoapod,127,0 +cocopod,127,0 +cpod,127,0 +sandstonestairs,128,0 +sandstairs,128,0 +sandsstairs,128,0 +sstonestairs,128,0 +ssstairs,128,0 +sandstair,128,0 +sandstonestair,128,0 +sandsstair,128,0 +sstonestair,128,0 +ssstair,128,0 +emeraldore,129,0 +eore,129,0 +oreemerald,129,0 +oree,129,0 +enderchest,130,0 +endchest,130,0 +echest,130,0 +chestender,130,0 +chestend,130,0 +cheste,130,0 +endercontainer,130,0 +endcontainer,130,0 +econtainer,130,0 +tripwirehook,131,0 +tripwire,131,0 +trip,131,0 +tripwirelever,131,0 +triphook,131,0 +emeraldblock,133,0 +blockemerald,133,0 +eblock,133,0 +blocke,133,0 +sprucewoodenstairs,134,0 +sprucewoodstairs,134,0 +sprucewstairs,134,0 +sprucestairs,134,0 +darkwoodenstairs,134,0 +darkwoodstairs,134,0 +darkwstairs,134,0 +darkstairs,134,0 +dstairs,134,0 +sprucewoodenstair,134,0 +sprucewoodstair,134,0 +sprucewstair,134,0 +sprucestair,134,0 +darkwoodenstair,134,0 +darkwoodstair,134,0 +darkwstair,134,0 +darkstair,134,0 +dstair,134,0 +birchwoodenstairs,135,0 +birchwoodstairs,135,0 +birchwstairs,135,0 +birchstairs,135,0 +lightwoodenstairs,135,0 +lightwoodstairs,135,0 +lightwstairs,135,0 +lightstairs,135,0 +lstairs,135,0 +birchwoodenstair,135,0 +birchwoodstair,135,0 +birchwstair,135,0 +birchstair,135,0 +lightwoodenstair,135,0 +lightwoodstair,135,0 +lightwstair,135,0 +lightstair,135,0 +lstair,135,0 +junglewoodenstairs,136,0 +junglewoodstairs,136,0 +junglewstairs,136,0 +junglestairs,136,0 +jstairs,136,0 +forestwoodenstairs,136,0 +forestwoodstairs,136,0 +forestwstairs,136,0 +foreststairs,136,0 +fstairs,136,0 +junglewoodenstair,136,0 +junglewoodstair,136,0 +junglewstair,136,0 +junglestair,136,0 +jstair,136,0 +forestwoodenstair,136,0 +forestwoodstair,136,0 +forestwstair,136,0 +foreststair,136,0 +fstair,136,0 +commandblock,137,0 +blockcommand,137,0 +cmdblock,137,0 +blockcmd,137,0 +macroblock,137,0 +blockmacro,137,0 +beacon,138,0 +beaconblock,138,0 +cobblestonewall,139,0 +cstonewall,139,0 +cobblewall,139,0 +cobblestonefence,139,0 +cstonefence,139,0 +cobblefence,139,0 +cswall,139,0 +csfence,139,0 +cwall,139,0 +cfence,139,0 +mosscobblestonewall,139,1 +mosscstonewall,139,1 +mosscobblewall,139,1 +mcobblestonewall,139,1 +mcstonewall,139,1 +mcobblewall,139,1 +mosscobblestonefence,139,1 +mosscstonefence,139,1 +mosscobblefence,139,1 +mcobblestonefence,139,1 +mcstonefence,139,1 +mcobblefence,139,1 +mcswall,139,0 +mcsfence,139,0 +mcwall,139,0 +mcfence,139,0 +plantedcarrot,141,0 +plantcarrot,141,0 +carrots,141,0 +growingcarrot,141,0 +potatoplant,142,0 +potatoes,142,0 +plantedpotato,142,0 +plantpotato,142,0 +growingpotato,142,0 +woodenbutton,143,0 +woodenplankbutton,143,0 +woodplankbutton,143,0 +wplankbutton,143,0 +plankbutton,143,0 +woodbutton,143,0 +wbutton,143,0 +anvil,145,0 +slightlydamagedanvil,145,1 +slightdamageanvil,145,1 +damagedanvil,145,1 +verydamagedanvil,145,2 +trapchest,146,0 +trappedchest,146,0 +chesttrapped,146,0 +chesttrap,146,0 +goldpressureplate,147,0 +weightedgoldpressureplate,147,0 +weightgoldpressureplate,147,0 +wgoldpressureplate,147,0 +weightedgoldpressplate,147,0 +weightgoldpressplate,147,0 +wgoldpressplate,147,0 +goldpressplate,147,0 +weightedgoldpplate,147,0 +weightgoldpplate,147,0 +wgoldpplate,147,0 +goldpplate,147,0 +weightedgoldplate,147,0 +weightgoldplate,147,0 +wgoldplate,147,0 +goldplate,147,0 +weightedgpressureplate,147,0 +weightgpressureplate,147,0 +wgpressureplate,147,0 +gpressureplate,147,0 +weightedgpressplate,147,0 +weightgpressplate,147,0 +wgpressplate,147,0 +gpressplate,147,0 +weightedgpplate,147,0 +weightgpplate,147,0 +wgpplate,147,0 +gpplate,147,0 +weightedgplate,147,0 +weightgplate,147,0 +wgplate,147,0 +gplate,147,0 +ironpressureplate,148,0 +weightedironpressureplate,148,0 +weightironpressureplate,148,0 +wironpressureplate,148,0 +weightedironpressplate,148,0 +weightironpressplate,148,0 +wironpressplate,148,0 +ironpressplate,148,0 +weightedironpplate,148,0 +weightironpplate,148,0 +wironpplate,148,0 +ironpplate,148,0 +weightedironplate,148,0 +weightironplate,148,0 +wironplate,148,0 +ironplate,148,0 +weightedipressureplate,148,0 +weightipressureplate,148,0 +wipressureplate,148,0 +ipressureplate,148,0 +weightedipressplate,148,0 +weightipressplate,148,0 +wipressplate,148,0 +ipressplate,148,0 +weightedipplate,148,0 +weightipplate,148,0 +wipplate,148,0 +ipplate,148,0 +weightediplate,148,0 +weightiplate,148,0 +wiplate,148,0 +iplate,148,0 +daylightsensor,151,0 +daylightsense,151,0 +lightsensor,151,0 +lightsense,151,0 +daysensor,151,0 +daysense,151,0 +timesensor,151,0 +timesense,151,0 +redstoneblock,152,0 +rstoneblock,152,0 +redsblock,152,0 +rsblock,152,0 +blockredstone,152,0 +blockrstone,152,0 +blockreds,152,0 +blockrs,152,0 +netherquartzore,153,0 +hellquartzore,153,0 +deathquartzore,153,0 +nquartzore,153,0 +hquartzore,153,0 +dquartzore,153,0 +quartzore,153,0 +netherqore,153,0 +hellqore,153,0 +deathqore,153,0 +nqore,153,0 +hqore,153,0 +dqore,153,0 +qore,153,0 +hopper,154,0 +chestpuller,154,0 +chestpull,154,0 +cheststorer,154,0 +cheststore,154,0 +itempuller,154,0 +itempull,154,0 +itemstorer,154,0 +itemstore,154,0 +quartzblock,155,0 +netherquartzblock,155,0 +nqblock,155,0 +qblock,155,0 +chiseledquartzblock,155,1 +chiselquartzblock,155,1 +cquartzblock,155,1 +cqblock,155,1 +pillarquartzblock,155,2 +pquartzblock,155,2 +pqblock,155,2 +quartzstairs,156,0 +qstairs,156,0 +quartzstair,156,0 +qstair,156,0 +activatorrails,157,0 +activaterails,157,0 +triggerrails,157,0 +arails,157,0 +trails,157,0 +activatorrail,157,0 +activaterail,157,0 +triggerrail,157,0 +arail,157,0 +trail,157,0 +activatortrack,157,0 +activatetrack,157,0 +triggertrack,157,0 +atrack,157,0 +ttrack,157,0 +dropper,158,0 +drop,158,0 +chestdispenser,158,0 +chestdispense,158,0 +chestdropper,158,0 +chestdrop,158,0 +whiteclay,159,0 +whitesclay,159,0 +whitestainedclay,159,0 +wclay,159,0 +wsclay,159,0 +wstainedclay,159,0 +sclay,159,0 +stainedclay,159,0 +orangeclay,159,1 +orangesclay,159,1 +orangestainedclay,159,1 +oclay,159,1 +osclay,159,1 +ostainedclay,159,1 +magentaclay,159,2 +magentasclay,159,2 +magentastainedclay,159,2 +mclay,159,2 +msclay,159,2 +mstainedclay,159,2 +lightblueclay,159,3 +lightbluesclay,159,3 +lightbluestainedclay,159,3 +lblueclay,159,3 +lbluesclay,159,3 +lbluestainedclay,159,3 +lightbluclay,159,3 +lightblusclay,159,3 +lightblustainedclay,159,3 +lbluclay,159,3 +lblusclay,159,3 +lblustainedclay,159,3 +lbclay,159,3 +lbsclay,159,3 +lbstainedclay,159,3 +yellowclay,159,4 +yellowsclay,159,4 +yellowstainedclay,159,4 +yclay,159,4 +ysclay,159,4 +ystainedclay,159,4 +lightgreenclay,159,5 +lightgreensclay,159,5 +lightgreenstainedclay,159,5 +lgreenclay,159,5 +lgreensclay,159,5 +lgreenstainedclay,159,5 +lightgreclay,159,5 +lightgresclay,159,5 +lightgrestainedclay,159,5 +lgreclay,159,5 +lgresclay,159,5 +lgrestainedclay,159,5 +limeclay,159,5 +limesclay,159,5 +limestainedclay,159,5 +lclay,159,5 +lsclay,159,5 +lstainedclay,159,5 +pinkclay,159,6 +pinksclay,159,6 +pinkstainedclay,159,6 +piclay,159,6 +pisclay,159,6 +pistainedclay,159,6 +darkgrayclay,159,7 +darkgraysclay,159,7 +darkgraystainedclay,159,7 +dgrayclay,159,7 +dgraysclay,159,7 +dgraystainedclay,159,7 +darkgreyclay,159,7 +darkgreeysclay,159,7 +darkgreystainedclay,159,7 +dgreyclay,159,7 +dgreysclay,159,7 +dgreystainedclay,159,7 +darkgraclay,159,7 +darkgrasclay,159,7 +darkgrastainedclay,159,7 +dgraclay,159,7 +dgrasclay,159,7 +dgrastainedclay,159,7 +grayclay,159,7 +graysclay,159,7 +graystainedclay,159,7 +greyclay,159,7 +greysclay,159,7 +greystainedclay,159,7 +graclay,159,7 +grasclay,159,7 +grastainedclay,159,7 +lightgrayclay,159,8 +lightgraysclay,159,8 +lightgraystainedclay,159,8 +lgrayclay,159,8 +lgraysclay,159,8 +lgraystainedclay,159,8 +lightgreyclay,159,8 +lightgreysclay,159,8 +lightgreystainedclay,159,8 +lgreyclay,159,8 +lgreysclay,159,8 +lgreystainedclay,159,8 +lightgraclay,159,8 +lightgrasclay,159,8 +lightgrastainedclay,159,8 +lgraclay,159,8 +lgrasclay,159,8 +lgrastainedclay,159,8 +silverclay,159,8 +silversclay,159,8 +silverstainedclay,159,8 +siclay,159,8 +siasclay,159,8 +siastainedclay,159,8 +cyanclay,159,9 +cyansclay,159,9 +cyanstainedclay,159,9 +cclay,159,9 +csclay,159,9 +cstainedclay,159,9 +purpleclay,159,10 +purplesclay,159,10 +purplestainedclay,159,10 +puclay,159,10 +pusclay,159,10 +pustainedclay,159,10 +blueclay,159,11 +bluesclay,159,11 +bluestainedclay,159,11 +bluclay,159,11 +blusclay,159,11 +blustainedclay,159,11 +brownclay,159,12 +brownsclay,159,12 +brownstainedclay,159,12 +broclay,159,12 +brosclay,159,12 +brostainedclay,159,12 +darkgreenclay,159,13 +darkgreensclay,159,13 +darkgreenstainedclay,159,13 +dgreenclay,159,13 +dgreensclay,159,13 +dgreenstainedclay,159,13 +greenclay,159,13 +greensclay,159,13 +greenstainedclay,159,13 +darkgreclay,159,13 +darkgresclay,159,13 +darkgrestainedclay,159,13 +dgreclay,159,13 +dgresclay,159,13 +dgrestainedclay,159,13 +greclay,159,13 +gresclay,159,13 +grestainedclay,159,13 +redclay,159,14 +redsclay,159,14 +redstainedclay,159,14 +rclay,159,14 +rsclay,159,14 +rstainedclay,159,14 +blackclay,159,15 +blacksclay,159,15 +blackstainedclay,159,15 +blaclay,159,15 +blasclay,159,15 +blastainedclay,159,15 +whiteglasspane,160,0 +whitesglasspane,160,0 +whitestainedglasspane,160,0 +wglasspane,160,0 +wsglasspane,160,0 +wstainedglasspane,160,0 +sglasspane,160,0 +stainedglasspane,160,0 +orangeglasspane,160,1 +orangesglasspane,160,1 +orangestainedglasspane,160,1 +oglasspane,160,1 +osglasspane,160,1 +ostainedglasspane,160,1 +magentaglasspane,160,2 +magentasglasspane,160,2 +magentastainedglasspane,160,2 +mglasspane,160,2 +msglasspane,160,2 +mstainedglasspane,160,2 +lightblueglasspane,160,3 +lightbluesglasspane,160,3 +lightbluestainedglasspane,160,3 +lblueglasspane,160,3 +lbluesglasspane,160,3 +lbluestainedglasspane,160,3 +lightbluglasspane,160,3 +lightblusglasspane,160,3 +lightblustainedglasspane,160,3 +lbluglasspane,160,3 +lblusglasspane,160,3 +lblustainedglasspane,160,3 +lbglasspane,160,3 +lbsglasspane,160,3 +lbstainedglasspane,160,3 +yellowglasspane,160,4 +yellowsglasspane,160,4 +yellowstainedglasspane,160,4 +yglasspane,160,4 +ysglasspane,160,4 +ystainedglasspane,160,4 +lightgreenglasspane,160,5 +lightgreensglasspane,160,5 +lightgreenstainedglasspane,160,5 +lgreenglasspane,160,5 +lgreensglasspane,160,5 +lgreenstainedglasspane,160,5 +lightgreglasspane,160,5 +lightgresglasspane,160,5 +lightgrestainedglasspane,160,5 +lgreglasspane,160,5 +lgresglasspane,160,5 +lgrestainedglasspane,160,5 +limeglasspane,160,5 +limesglasspane,160,5 +limestainedglasspane,160,5 +lglasspane,160,5 +lsglasspane,160,5 +lstainedglasspane,160,5 +pinkglasspane,160,6 +pinksglasspane,160,6 +pinkstainedglasspane,160,6 +piglasspane,160,6 +pisglasspane,160,6 +pistainedglasspane,160,6 +darkgrayglasspane,160,7 +darkgraysglasspane,160,7 +darkgraystainedglasspane,160,7 +dgrayglasspane,160,7 +dgraysglasspane,160,7 +dgraystainedglasspane,160,7 +darkgreyglasspane,160,7 +darkgreysglasspane,160,7 +darkgreystainedglasspane,160,7 +dgreyglasspane,160,7 +dgreysglasspane,160,7 +dgreystainedglasspane,160,7 +darkgraglasspane,160,7 +darkgrasglasspane,160,7 +darkgrastainedglasspane,160,7 +dgraglasspane,160,7 +dgrasglasspane,160,7 +dgrastainedglasspane,160,7 +grayglasspane,160,7 +graysglasspane,160,7 +graystainedglasspane,160,7 +greyglasspane,160,7 +greysglasspane,160,7 +greystainedglasspane,160,7 +graglasspane,160,7 +grasglasspane,160,7 +grastainedglasspane,160,7 +lightgrayglasspane,160,8 +lightgraysglasspane,160,8 +lightgraystainedglasspane,160,8 +lgrayglasspane,160,8 +lgraysglasspane,160,8 +lgraystainedglasspane,160,8 +lightgreyglasspane,160,8 +lightgreysglasspane,160,8 +lightgreystainedglasspane,160,8 +lgreyglasspane,160,8 +lgreysglasspane,160,8 +lgreystainedglasspane,160,8 +lightgraglasspane,160,8 +lightgrasglasspane,160,8 +lightgrastainedglasspane,160,8 +lgraglasspane,160,8 +lgrasglasspane,160,8 +lgrastainedglasspane,160,8 +silverglasspane,160,8 +silversglasspane,160,8 +silverstainedglasspane,160,8 +siglasspane,160,8 +siasglasspane,160,8 +siastainedglasspane,160,8 +cyanglasspane,160,9 +cyansglasspane,160,9 +cyanstainedglasspane,160,9 +cglasspane,160,9 +csglasspane,160,9 +cstainedglasspane,160,9 +purpleglasspane,160,10 +purplesglasspane,160,10 +purplestainedglasspane,160,10 +puglasspane,160,10 +pusglasspane,160,10 +pustainedglasspane,160,10 +blueglasspane,160,11 +bluesglasspane,160,11 +bluestainedglasspane,160,11 +bluglasspane,160,11 +blusglasspane,160,11 +blustainedglasspane,160,11 +brownglasspane,160,12 +brownsglasspane,160,12 +brownstainedglasspane,160,12 +broglasspane,160,12 +brosglasspane,160,12 +brostainedglasspane,160,12 +darkgreenglasspane,160,13 +darkgreensglasspane,160,13 +darkgreenstainedglasspane,160,13 +dgreenglasspane,160,13 +dgreensglasspane,160,13 +dgreenstainedglasspane,160,13 +greenglasspane,160,13 +greensglasspane,160,13 +greenstainedglasspane,160,13 +darkgreglasspane,160,13 +darkgresglasspane,160,13 +darkgrestainedglasspane,160,13 +dgreglasspane,160,13 +dgresglasspane,160,13 +dgrestainedglasspane,160,13 +greglasspane,160,13 +gresglasspane,160,13 +grestainedglasspane,160,13 +redglasspane,160,14 +redsglasspane,160,14 +redstainedglasspane,160,14 +rglasspane,160,14 +rsglasspane,160,14 +rstainedglasspane,160,14 +blackglasspane,160,15 +blacksglasspane,160,15 +blackstainedglasspane,160,15 +blaglasspane,160,15 +blasglasspane,160,15 +blastainedglasspane,160,15 +acacialeaves,161,0 +acaciatreeleaves,161,0 +acacialogleaves,161,0 +acaciatrunkleaves,161,0 +acaciawoodleaves,161,0 +aleaves,161,0 +atreeleaves,161,0 +alogleaves,161,0 +atrunkleaves,161,0 +awoodleaves,161,0 +acacialeave,161,0 +acaciatreeleave,161,0 +acacialogleave,161,0 +acaciatrunkleave,161,0 +acaciawoodleave,161,0 +aleave,161,0 +atreeleave,161,0 +alogleave,161,0 +atrunkleave,161,0 +awoodleave,161,0 +acaciatreeleaf,161,0 +acacialogleaf,161,0 +acaciatrunkleaf,161,0 +acaciawoodleaf,161,0 +aleaf,161,0 +atreeleaf,161,0 +alogleaf,161,0 +atrunkleaf,161,0 +awoodleaf,161,0 +darkoakleaves,161,1 +darkoaktreeleaves,161,1 +darkoaklogleaves,161,1 +darkoaktrunkleaves,161,1 +darkoakwoodleaves,161,1 +doakleaves,161,1 +doaktreeleaves,161,1 +doaklogleaves,161,1 +doaktrunkleaves,161,1 +doakwoodleaves,161,1 +doleaves,161,1 +dotreeleaves,161,1 +dologleaves,161,1 +dotrunkleaves,161,1 +dowoodleaves,161,1 +darkoakleave,161,1 +darkoaktreeleave,161,1 +darkoaklogleave,161,1 +darkoaktrunkleave,161,1 +darkoakwoodleave,161,1 +doakleave,161,1 +doaktreeleave,161,1 +doaklogleave,161,1 +doaktrunkleave,161,1 +doakwoodleave,161,1 +doleave,161,1 +dotreeleave,161,1 +dologleave,161,1 +dotrunkleave,161,1 +dowoodleave,161,1 +darkoaktreeleaf,161,1 +darkoaklogleaf,161,1 +darkoaktrunkleaf,161,1 +darkoakwoodleaf,161,1 +doakleaf,161,1 +doaktreeleaf,161,1 +doaklogleaf,161,1 +doaktrunkleaf,161,1 +doakwoodleaf,161,1 +doleaf,161,1 +dotreeleaf,161,1 +dologleaf,161,1 +dotrunkleaf,161,1 +dowoodleaf,161,1 +acacia,162,0 +acaciatree,162,0 +acacialog,162,0 +acaciatrunk,162,0 +acaciawood,162,0 +atree,162,0 +alog,162,0 +atrunk,162,0 +awood,162,0 +darkoak,162,1 +darkoaktree,162,1 +darkoaklog,162,1 +darkoaktrunk,162,1 +darkoakwood,162,1 +doak,162,1 +doaktree,162,1 +doaklog,162,1 +doaktrunk,162,1 +doakwood,162,1 +dotree,162,1 +dolog,162,1 +dotrunk,162,1 +dowood,162,1 +acaciawoodenstairs,163,0 +acaciawoodstairs,163,0 +acaciawstairs,163,0 +acaciastairs,163,0 +awoodenstairs,163,0 +awoodstairs,163,0 +awstairs,163,0 +astairs,163,0 +acaciawoodenstair,163,0 +acaciawoodstair,163,0 +acaciawstair,163,0 +acaciastair,163,0 +awoodenstair,163,0 +awoodstair,163,0 +awstair,163,0 +astair,163,0 +darkoakwoodenstairs,164,0 +darkoakwoodstairs,164,0 +darkoakwstairs,164,0 +darkoakstairs,164,0 +doakwoodenstairs,164,0 +doakwoodstairs,164,0 +doakwstairs,164,0 +doakstairs,164,0 +dowoodenstairs,164,0 +dowoodstairs,164,0 +dowstairs,164,0 +dostairs,164,0 +darkoakwoodenstair,164,0 +darkoakwoodstair,164,0 +darkoakwstair,164,0 +darkoakstair,164,0 +doakwoodenstair,164,0 +doakwoodstair,164,0 +doakwstair,164,0 +doakstair,164,0 +dowoodenstair,164,0 +dowoodstair,164,0 +dowstair,164,0 +dostair,164,0 +hay,170,0 +hayblock,170,0 +haybale,170,0 +baleofhay,170,0 +hayofbale,170,0 +whitecarpet,171,0 +whitefloor,171,0 +wcarpet,171,0 +wfloor,171,0 +carpet,171,0 +floor,171,0 +orangecarpet,171,1 +orangefloor,171,1 +ocarpet,171,1 +ofloor,171,1 +magentacarpet,171,2 +magentafloor,171,2 +mcarpet,171,2 +mfloor,171,2 +lightbluecarpet,171,3 +lightbluefloor,171,3 +lbluecarpet,171,3 +lbluefloor,171,3 +lbcarpet,171,3 +lbfloor,171,3 +lightblucarpet,171,3 +lightblufloor,171,3 +lblucarpet,171,3 +lblufloor,171,3 +yellowcarpet,171,4 +yellowfloor,171,4 +ycarpet,171,4 +yfloor,171,4 +lightgreencarpet,171,5 +lightgreenfloor,171,5 +lgreencarpet,171,5 +lgreenfloor,171,5 +lightgrecarpet,171,5 +lightgrefloor,171,5 +lgrecarpet,171,5 +lgrefloor,171,5 +limecarpet,171,5 +limefloor,171,5 +lcarpet,171,5 +lfloor,171,5 +pinkcarpet,171,6 +pinkfloor,171,6 +picarpet,171,6 +pifloor,171,6 +darkgraycarpet,171,7 +darkgrayfloor,171,7 +dgraycarpet,171,7 +dgrayfloor,171,7 +darkgreycarpet,171,7 +darkgreyfloor,171,7 +dgreycarpet,171,7 +dgreyfloor,171,7 +darkgracarpet,171,7 +darkgrafloor,171,7 +dgracarpet,171,7 +dgrafloor,171,7 +graycarpet,171,7 +grayfloor,171,7 +greycarpet,171,7 +greyfloor,171,7 +gracarpet,171,7 +grafloor,171,7 +lightgraycarpet,171,8 +lightgrayfloor,171,8 +lgraycarpet,171,8 +lgrayfloor,171,8 +lightgreycarpet,171,8 +lightgreyfloor,171,8 +lgreycarpet,171,8 +lgreyfloor,171,8 +lightgracarpet,171,8 +lightgrafloor,171,8 +lgracarpet,171,8 +lgrafloor,171,8 +silvercarpet,171,8 +silverfloor,171,8 +sicarpet,171,8 +siafloor,171,8 +cyancarpet,171,9 +cyanfloor,171,9 +ccarpet,171,9 +cfloor,171,9 +purplecarpet,171,10 +purplefloor,171,10 +pucarpet,171,10 +pufloor,171,10 +bluecarpet,171,11 +bluefloor,171,11 +blucarpet,171,11 +blufloor,171,11 +browncarpet,171,12 +brownfloor,171,12 +brocarpet,171,12 +brofloor,171,12 +darkgreencarpet,171,13 +darkgreenfloor,171,13 +dgreencarpet,171,13 +dgreenfloor,171,13 +greencarpet,171,13 +greenfloor,171,13 +darkgrecarpet,171,13 +darkgrefloor,171,13 +dgrecarpet,171,13 +dgrefloor,171,13 +grecarpet,171,13 +grefloor,171,13 +redcarpet,171,14 +redfloor,171,14 +rcarpet,171,14 +rfloor,171,14 +blackcarpet,171,15 +blackfloor,171,15 +blacarpet,171,15 +blafloor,171,15 +hardenedclay,172,0 +hardclay,172,0 +hclay,172,0 +coalblock,173,0 +blockcoal,173,0 +coblock,173,0 +blockco,173,0 +coalb,173,0 +bcoal,173,0 +packedice,174,0 +packice,174,0 +solidice,174,0 +sunflower,175,0 +yellowsunflower,175,0 +lilac,175,1 +magentalilac,175,1 +syringa,175,1 +longtallgrass,175,2 +extratallgrass,175,2 +doubletallgrass,175,2 +largetallgrass,175,2 +longtgrass,175,2 +extratgrass,175,2 +doubletgrass,175,2 +largetgrass,175,2 +ltgrass,175,2 +etgrass,175,2 +dtgrass,175,2 +bigfern,175,3 +largefern,175,3 +doublefern,175,3 +bfern,175,3 +lfern,175,3 +dfern,175,3 +rosebush,175,4 +redrosebush,175,4 +peony,175,5 +pinkpeony,175,5 +paeonia,175,5 +ironshovel,256,0 +ironspade,256,0 +ishovel,256,0 +ispade,256,0 +steelshovel,256,0 +steelspade,256,0 +ironpickaxe,257,0 +ironpick,257,0 +steelpickaxe,257,0 +steelpick,257,0 +ipickaxe,257,0 +ipick,257,0 +ironaxe,258,0 +iaxe,258,0 +steelaxe,258,0 +flintandsteel,259,0 +flintandiron,259,0 +flintandtinder,259,0 +flintnsteel,259,0 +flintniron,259,0 +flintntinder,259,0 +flintsteel,259,0 +flintiron,259,0 +flinttinder,259,0 +lighter,259,0 +apple,260,0 +normalapple,260,0 +redapple,260,0 +bow,261,0 +arrow,262,0 +coal,263,0 +charcoal,263,1 +ccoal,263,1 +diamond,264,0 +crystal,264,0 +ironingot,265,0 +ironbar,265,0 +ironi,265,0 +steelingot,265,0 +steelbar,265,0 +steeli,265,0 +iingot,265,0 +ibar,265,0 +ingotiron,265,0 +bariron,265,0 +iiron,265,0 +ingotsteel,265,0 +barsteel,265,0 +isteel,265,0 +ingoti,265,0 +bari,265,0 +goldingot,266,0 +goldbar,266,0 +goldi,266,0 +gingot,266,0 +gbar,266,0 +ingotgold,266,0 +bargold,266,0 +igold,266,0 +ingotg,266,0 +barg,266,0 +ironsword,267,0 +steelsword,267,0 +isword,267,0 +woodensword,268,0 +woodsword,268,0 +wsword,268,0 +woodenshovel,269,0 +woodenspade,269,0 +woodshovel,269,0 +woodspade,269,0 +wshovel,269,0 +wspade,269,0 +woodenpickaxe,270,0 +woodenpick,270,0 +woodpickaxe,270,0 +woodpick,270,0 +wpickaxe,270,0 +wpick,270,0 +woodenaxe,271,0 +woodaxe,271,0 +waxe,271,0 +stonesword,272,0 +cobblestonesword,272,0 +cstonesword,272,0 +cssword,272,0 +ssword,272,0 +stoneshovel,273,0 +cobblestoneshovel,273,0 +cobblestonespade,273,0 +cstoneshovel,273,0 +cstonespade,273,0 +stonespade,273,0 +csshovel,273,0 +csspade,273,0 +sshovel,273,0 +sspade,273,0 +stonepickaxe,274,0 +cobblestonepickaxe,274,0 +cobblestonepick,274,0 +cstonepickaxe,274,0 +cstonepick,274,0 +stonepick,274,0 +cspickaxe,274,0 +cspick,274,0 +spickaxe,274,0 +spick,274,0 +stoneaxe,275,0 +cobblestoneaxe,275,0 +cstoneaxe,275,0 +csaxe,275,0 +saxe,275,0 +diamondsword,276,0 +crystalsword,276,0 +dsword,276,0 +diamondshovel,277,0 +diamondspade,277,0 +crystalshovel,277,0 +crystalspade,277,0 +dshovel,277,0 +dspade,277,0 +diamondpickaxe,278,0 +diamondpick,278,0 +crystalpickaxe,278,0 +crystalpick,278,0 +dpickaxe,278,0 +dpick,278,0 +diamondaxe,279,0 +crystalaxe,279,0 +daxe,279,0 +stick,280,0 +twig,280,0 +branch,280,0 +bowl,281,0 +woodenbowl,281,0 +woodbowl,281,0 +mushroomsoup,282,0 +mrsoup,282,0 +soup,282,0 +goldsword,283,0 +gsword,283,0 +goldshovel,284,0 +goldspade,284,0 +gshovel,284,0 +gspade,284,0 +goldpickaxe,285,0 +goldpick,285,0 +gpickaxe,285,0 +gpick,285,0 +goldaxe,286,0 +gaxe,286,0 +string,287,0 +thread,287,0 +feather,288,0 +gunpowder,289,0 +sulfur,289,0 +woodenhoe,290,0 +woodhoe,290,0 +whoe,290,0 +stonehoe,291,0 +cobblestonehoe,291,0 +cstonehoe,291,0 +cshoe,291,0 +shoe,291,0 +ironhoe,292,0 +steelhoe,292,0 +ihoe,292,0 +diamondhoe,293,0 +crystalhoe,293,0 +dhoe,293,0 +goldhoe,294,0 +ghoe,294,0 +seeds,295,0 +seed,295,0 +wheat,296,0 +crops,296,0 +crop,296,0 +bread,297,0 +leatherhelmet,298,0 +leatherhelm,298,0 +leatherhat,298,0 +leathercoif,298,0 +lhelmet,298,0 +lhelm,298,0 +lhat,298,0 +lcoif,298,0 +leatherchestplate,299,0 +leatherplatebody,299,0 +leatherplate,299,0 +leathershirt,299,0 +leathertunic,299,0 +lchestplate,299,0 +lplatebody,299,0 +lplate,299,0 +lshirt,299,0 +ltunic,299,0 +leatherleggings,300,0 +leatherlegs,300,0 +leatherpants,300,0 +lleggings,300,0 +llegs,300,0 +lpants,300,0 +leatherboots,301,0 +leathershoes,301,0 +lboots,301,0 +lshoes,301,0 +chainmailhelmet,302,0 +chainmailhelm,302,0 +chainmailhat,302,0 +chainmailcoif,302,0 +chainmhelmet,302,0 +chainmhelm,302,0 +chainmhat,302,0 +chainmcoif,302,0 +cmailhelmet,302,0 +cmailhelm,302,0 +cmailhat,302,0 +cmailcoif,302,0 +chainhelmet,302,0 +chainhelm,302,0 +chainhat,302,0 +chaincoif,302,0 +cmhelmet,302,0 +cmhelm,302,0 +cmhat,302,0 +cmcoif,302,0 +chainmailchestplate,303,0 +chainmailplatebody,303,0 +chainmailplate,303,0 +chainmailshirt,303,0 +chainmailtunic,303,0 +chainmchestplate,303,0 +chainmplatebody,303,0 +chainmplate,303,0 +chainmshirt,303,0 +chainmtunic,303,0 +cmailchestplate,303,0 +cmailplatebody,303,0 +cmailplate,303,0 +cmailshirt,303,0 +cmailtunic,303,0 +chainchestplate,303,0 +chainplatebody,303,0 +chainplate,303,0 +chainshirt,303,0 +chaintunic,303,0 +cmchestplate,303,0 +cmplatebody,303,0 +cmplate,303,0 +cmshirt,303,0 +cmtunic,303,0 +chainmailleggings,304,0 +chainmaillegs,304,0 +chainmailpants,304,0 +chainmleggings,304,0 +chainmlegs,304,0 +chainmpants,304,0 +cmailleggings,304,0 +cmaillegs,304,0 +cmailpants,304,0 +chainleggings,304,0 +chainlegs,304,0 +chainpants,304,0 +cmleggings,304,0 +cmlegs,304,0 +cmpants,304,0 +chainmailboots,305,0 +chainmailshoes,305,0 +chainmboots,305,0 +chainmshoes,305,0 +cmailboots,305,0 +cmailshoes,305,0 +chainboots,305,0 +chainshoes,305,0 +cmboots,305,0 +cmshoes,305,0 +ironhelmet,306,0 +ironhelm,306,0 +ironhat,306,0 +ironcoif,306,0 +ihelmet,306,0 +ihelm,306,0 +ihat,306,0 +icoif,306,0 +steelhelmet,306,0 +steelhelm,306,0 +steelhat,306,0 +steelcoif,306,0 +shelmet,306,0 +shelm,306,0 +shat,306,0 +scoif,306,0 +ironchestplate,307,0 +ironplatebody,307,0 +ironshirt,307,0 +irontunic,307,0 +ichestplate,307,0 +iplatebody,307,0 +ishirt,307,0 +itunic,307,0 +steelchestplate,307,0 +steelplatebody,307,0 +steelplate,307,0 +steelshirt,307,0 +steeltunic,307,0 +schestplate,307,0 +splatebody,307,0 +sshirt,307,0 +stunic,307,0 +ironleggings,308,0 +ironlegs,308,0 +ironpants,308,0 +ileggings,308,0 +ilegs,308,0 +ipants,308,0 +steelleggings,308,0 +steellegs,308,0 +steelpants,308,0 +sleggings,308,0 +slegs,308,0 +spants,308,0 +ironboots,309,0 +ironshoes,309,0 +iboots,309,0 +ishoes,309,0 +steelboots,309,0 +steelshoes,309,0 +sboots,309,0 +sshoes,309,0 +diamondhelmet,310,0 +diamondhelm,310,0 +diamondhat,310,0 +diamondcoif,310,0 +dhelmet,310,0 +dhelm,310,0 +dhat,310,0 +dcoif,310,0 +crystalhelmet,310,0 +crystalhelm,310,0 +crystalhat,310,0 +crystalcoif,310,0 +chelmet,310,0 +chelm,310,0 +chat,310,0 +ccoif,310,0 +diamondchestplate,311,0 +diamondplatebody,311,0 +diamondplate,311,0 +diamondshirt,311,0 +diamondtunic,311,0 +dchestplate,311,0 +dplatebody,311,0 +dplate,311,0 +dshirt,311,0 +dtunic,311,0 +crystalchestplate,311,0 +crystalplatebody,311,0 +crystalplate,311,0 +crystalshirt,311,0 +crystaltunic,311,0 +cchestplate,311,0 +cplatebody,311,0 +cplate,311,0 +cshirt,311,0 +ctunic,311,0 +diamondleggings,312,0 +diamondlegs,312,0 +diamondpants,312,0 +dleggings,312,0 +dlegs,312,0 +dpants,312,0 +crystalleggings,312,0 +crystallegs,312,0 +crystalpants,312,0 +cleggings,312,0 +clegs,312,0 +cpants,312,0 +diamondboots,313,0 +diamondshoes,313,0 +dboots,313,0 +dshoes,313,0 +crystalboots,313,0 +crystalshoes,313,0 +cboots,313,0 +cshoes,313,0 +goldhelmet,314,0 +goldhelm,314,0 +goldhat,314,0 +goldcoif,314,0 +ghelmet,314,0 +ghelm,314,0 +ghat,314,0 +gcoif,314,0 +goldchestplate,315,0 +goldplatebody,315,0 +goldshirt,315,0 +goldtunic,315,0 +gchestplate,315,0 +gplatebody,315,0 +gplateplate,315,0 +gshirt,315,0 +gtunic,315,0 +goldleggings,316,0 +goldlegs,316,0 +goldpants,316,0 +gleggings,316,0 +glegs,316,0 +gpants,316,0 +goldboots,317,0 +goldshoes,317,0 +gboots,317,0 +gshoes,317,0 +flint,318,0 +pork,319,0 +porkchop,319,0 +rawpork,319,0 +rpork,319,0 +rawporkchop,319,0 +rporkchop,319,0 +cookedpork,320,0 +grilledpork,320,0 +grillpork,320,0 +gpork,320,0 +cookpork,320,0 +cpork,320,0 +grilledporkchop,320,0 +grillporkchop,320,0 +gporkchop,320,0 +cookedporkchop,320,0 +cookporkchop,320,0 +cporkchop,320,0 +bacon,320,0 +painting,321,0 +picture,321,0 +goldenapple,322,0 +goldapple,322,0 +gapple,322,0 +enchantedgoldenapple,322,1 +enchantedgoldapple,322,1 +enchantedgapple,322,1 +supergoldenapple,322,1 +supergoldapple,322,1 +supergapple,322,1 +magicalgoldenapple,322,1 +magicalgoldapple,322,1 +magicalgapple,322,1 +magicgoldenapple,322,1 +magicgoldapple,322,1 +magicgapple,322,1 +egoldenapple,322,1 +egoldapple,322,1 +egapple,322,1 +sgoldenapple,322,1 +sgoldapple,322,1 +sgapple,322,1 +mgoldenapple,322,1 +mgoldapple,322,1 +mgapple,322,1 +sign,323,0 +woodendoor,324,0 +wooddoor,324,0 +wdoor,324,0 +door,324,0 +bucket,325,0 +bukkit,325,0 +waterbucket,326,0 +waterbukkit,326,0 +wbucket,326,0 +wbukkit,326,0 +magmabucket,327,0 +magmabukkit,327,0 +lavabucket,327,0 +lavabukkit,327,0 +lbucket,327,0 +lbukkit,327,0 +minecart,328,0 +mcart,328,0 +cart,328,0 +saddle,329,0 +irondoor,330,0 +idoor,330,0 +steeldoor,330,0 +sdoor,330,0 +dooriron,330,0 +doori,330,0 +doorsteel,330,0 +doors,330,0 +redstonedust,331,0 +redstone,331,0 +rstonedust,331,0 +rstone,331,0 +redsdust,331,0 +reddust,331,0 +rsdust,331,0 +rdust,331,0 +snow,332,0 +snowball,332,0 +snball,332,0 +sball,332,0 +boat,333,0 +leather,334,0 +cowhide,334,0 +hide,334,0 +milkbucket,335,0 +milkbukkit,335,0 +mbucket,335,0 +mbukkit,335,0 +claybrick,336,0 +brick,336,0 +redbrick,336,0 +rbrick,336,0 +clayball,337,0 +cball,337,0 +clay,337,0 +reeds,338,0 +reed,338,0 +sugarcane,338,0 +scane,338,0 +bamboo,338,0 +paper,339,0 +papyrus,339,0 +book,340,0 +slimeball,341,0 +slball,341,0 +chestminecart,342,0 +storageminecart,342,0 +storagemcart,342,0 +chestmcart,342,0 +storagecart,342,0 +chestcart,342,0 +sminecart,342,0 +cminecart,342,0 +smcart,342,0 +cmcart,342,0 +scart,342,0 +ccart,342,0 +furnaceminecart,343,0 +engineminecart,343,0 +poweredminecart,343,0 +powerminecart,343,0 +enginemcart,343,0 +poweredmcart,343,0 +powermcart,343,0 +furnacemcart,343,0 +enginecart,343,0 +poweredcart,343,0 +powercart,343,0 +furnacecart,343,0 +eminecart,343,0 +pminecart,343,0 +fminecart,343,0 +emcart,343,0 +pmcart,343,0 +fmcart,343,0 +ecart,343,0 +pcart,343,0 +fcart,343,0 +egg,344,0 +compass,345,0 +fishingrod,346,0 +fishrod,346,0 +frod,346,0 +rod,346,0 +watch,347,0 +goldwatch,347,0 +goldclock,347,0 +gwatch,347,0 +gclock,347,0 +clock,347,0 +glowstonedust,348,0 +glowingstonedust,348,0 +lightstonedust,348,0 +lbdust,348,0 +gbdust,348,0 +lsdust,348,0 +gsdust,348,0 +rawfish,349,0 +rafish,349,0 +fish,349,0 +rawsalmonfish,349,1 +rasalmonfish,349,1 +salmonfish,349,1 +rawsalmon,349,1 +rasalmon,349,1 +salmon,349,1 +sfish,349,1 +fishs,349,1 +rawclownfish,349,2 +raclownfish,349,2 +clownfish,349,2 +rawnemo,349,2 +ranemo,349,2 +nemo,349,2 +nemofish,349,2 +fishnemo,349,2 +clfish,349,2 +fishcl,349,2 +nfish,349,2 +fishn,349,2 +rawpufferfish,349,3 +rapufferfish,349,3 +pufferfish,349,3 +pufffish,349,3 +fishpuff,349,3 +pfish,349,3 +fishp,349,3 +cookedfish,350,0 +cookfish,350,0 +cfish,350,0 +grilledfish,350,0 +grillfish,350,0 +gfish,350,0 +roastedfish,350,0 +roastfish,350,0 +rofish,350,0 +cookedsalmonfish,350,1 +cooksalmonfish,350,1 +csalmonfish,350,1 +grilledsalmonfish,350,1 +grillsalmonfish,350,1 +gsalmonfish,350,1 +roastedsalmonfish,350,1 +roastsalmonfish,350,1 +rosalmonfish,350,1 +cookedsalmon,350,1 +cooksalmon,350,1 +csalmon,350,1 +grilledsalmon,350,1 +grillsalmon,350,1 +gsalmon,350,1 +roastedsalmon,350,1 +roastsalmon,350,1 +rosalmon,350,1 +dye,351,0 +inksack,351,0 +inksac,351,0 +isack,351,0 +isac,351,0 +sack,351,0 +sac,351,0 +blackinksack,351,0 +blackinksac,351,0 +blackisack,351,0 +blackisac,351,0 +blacksack,351,0 +blacksac,351,0 +inksackblack,351,0 +inksacblack,351,0 +isackblack,351,0 +isacblack,351,0 +sackblack,351,0 +sacblack,351,0 +blackinksackcolour,351,0 +blackinksaccolour,351,0 +blackisackcolour,351,0 +blackisaccolour,351,0 +blacksackcolour,351,0 +blacksaccolour,351,0 +inksackblackcolour,351,0 +inksacblackcolour,351,0 +isackblackcolour,351,0 +isacclackcolour,351,0 +sackblackcolour,351,0 +sacblackcolour,351,0 +blackinksackcolor,351,0 +blackinksaccolor,351,0 +blackisackcolor,351,0 +blackisaccolor,351,0 +blacksackcolor,351,0 +blacksaccolor,351,0 +inksackblackcolor,351,0 +inksacblackcolor,351,0 +isackblackcolor,351,0 +isacblackcolor,351,0 +sackblackcolor,351,0 +sacblackcolor,351,0 +blackinksackdye,351,0 +blackinksacdye,351,0 +blackisackdye,351,0 +blackisacdye,351,0 +blacksackdye,351,0 +blacksacdye,351,0 +inksackblackdye,351,0 +inksacblackdye,351,0 +isackblackdye,351,0 +isacclackdye,351,0 +sackblackdye,351,0 +sacblackdye,351,0 +blackcolor,351,0 +blackdye,351,0 +rosered,351,1 +roseredcolor,351,1 +roseredcolour,351,1 +rosereddye,351,1 +redrosecolor,351,1 +redrosecolour,351,1 +redrosedye,351,1 +redr,351,1 +redrcolor,351,1 +redrcolour,351,1 +redrdye,351,1 +redcolor,351,1 +redcolour,351,1 +reddye,351,1 +cactusgreen,351,2 +greencactus,351,2 +cactusgreencolour,351,2 +greencactuscolour,351,2 +cactusgreencolor,351,2 +greencactuscolor,351,2 +cactusgreendye,351,2 +greencactusdye,351,2 +greencolour,351,2 +greencolor,351,2 +greendye,351,2 +cocoabeans,351,3 +cocoabean,351,3 +cocobeans,351,3 +cocobean,351,3 +cbeans,351,3 +cbean,351,3 +beans,351,3 +bean,351,3 +browncocoabeans,351,3 +browncocoabean,351,3 +browncocobeans,351,3 +browncocobean,351,3 +browncbeans,351,3 +browncbean,351,3 +brownbeans,351,3 +brownbean,351,3 +brownb,351,3 +cocoabeanscolour,351,3 +cocoabeancolour,351,3 +cocobeanscolour,351,3 +cocobeancolour,351,3 +cbeanscolour,351,3 +cbeancolour,351,3 +beanscolour,351,3 +beancolour,351,3 +browncocoabeanscolour,351,3 +browncocoabeancolour,351,3 +browncocobeanscolour,351,3 +browncocobeancolour,351,3 +browncbeanscolour,351,3 +browncbeancolour,351,3 +brownbeanscolour,351,3 +brownbeancolour,351,3 +brownbcolour,351,3 +cocoabeanscolor,351,3 +cocoabeancolor,351,3 +cocobeanscolor,351,3 +cocobeancolor,351,3 +cbeanscolor,351,3 +cbeancolor,351,3 +beanscolor,351,3 +beancolor,351,3 +browncocoabeanscolor,351,3 +browncocoabeancolor,351,3 +browncocobeanscolor,351,3 +browncocobeancolor,351,3 +browncbeanscolor,351,3 +browncbeancolor,351,3 +brownbeanscolor,351,3 +brownbeancolor,351,3 +brownbcolor,351,3 +cocoabeansdye,351,3 +cocoabeandye,351,3 +cocobeansdye,351,3 +cocobeandye,351,3 +cbeansdye,351,3 +cbeandye,351,3 +beansdye,351,3 +beandye,351,3 +browncocoabeansdye,351,3 +browncocoabeandye,351,3 +browncocobeansdye,351,3 +browncocobeandye,351,3 +browncbeansdye,351,3 +browncbeandye,351,3 +brownbeansdye,351,3 +brownbeandye,351,3 +brownbdye,351,3 +browncolour,351,3 +browncolor,351,3 +browndye,351,3 +lapislazuli,351,4 +bluelapislazuli,351,4 +bluelapisl,351,4 +bluelapis,351,4 +bluel,351,4 +lapislazuliblue,351,4 +lapislblue,351,4 +lapisblue,351,4 +lapisl,351,4 +lapis,351,4 +bluelapislazulicolour,351,4 +bluelapislcolour,351,4 +bluelapiscolour,351,4 +lapislazulibluecolour,351,4 +lapislbluecolour,351,4 +lapisbluecolour,351,4 +lapislazulicolour,351,4 +lapislcolour,351,4 +lapiscolour,351,4 +bluelapislazulicolor,351,4 +bluelapislcolor,351,4 +bluelapiscolor,351,4 +lapislazulibluecolor,351,4 +lapislbluecolor,351,4 +lapisbluecolor,351,4 +lapislazulicolor,351,4 +lapislcolor,351,4 +lapiscolor,351,4 +bluelapislazulidye,351,4 +bluelapisldye,351,4 +bluelapisdye,351,4 +lapislazulibluedye,351,4 +lapislbluedye,351,4 +lapisbluedye,351,4 +lapislazulidye,351,4 +lapisldye,351,4 +lapisdye,351,4 +bluecolour,351,4 +bluecolor,351,4 +bluedye,351,4 +purpledye,351,5 +purplecolour,351,5 +purplecolor,351,5 +cyandye,351,6 +cyancolour,351,6 +cyancolor,351,6 +lightgraydye,351,7 +lightgraycolour,351,7 +lightgraycolor,351,7 +lgraycolour,351,7 +lgraycolor,351,7 +lgraydye,351,7 +lightgreydye,351,7 +lightgreycolour,351,7 +lightgreycolor,351,7 +lgreycolour,351,7 +lgreycolor,351,7 +lgreydye,351,7 +silvercolour,351,7 +silvercolor,351,7 +silverdye,351,7 +darkgraydye,351,8 +darkgraycolour,351,8 +darkgraycolor,351,8 +dgraycolour,351,8 +dgraycolor,351,8 +dgraydye,351,8 +graycolour,351,8 +graycolor,351,8 +graydye,351,8 +darkgreydye,351,8 +darkgreycolour,351,8 +darkgreycolor,351,8 +dgreycolour,351,8 +dgreycolor,351,8 +dgreydye,351,8 +greycolour,351,8 +greycolor,351,8 +greydye,351,8 +pinkdye,351,9 +pinkcolour,351,9 +pinkcolor,351,9 +limedye,351,10 +limecolour,351,10 +limecolor,351,10 +dandelionyellow,351,11 +dandelionyellowcolour,351,11 +dandelionyellowcolor,351,11 +dandelionyellowdye,351,11 +yellowdandelioncolour,351,11 +yellowdandelioncolor,351,11 +yellowdandeliondye,351,11 +yellowd,351,11 +yellowdcolour,351,11 +yellowdcolor,351,11 +yellowddye,351,11 +dyellow,351,11 +dyellowcolour,351,11 +dyellowcolor,351,11 +dyellowdye,351,11 +yellowcolour,351,11 +yellowcolor,351,11 +yellowdye,351,11 +lightbluecolour,351,12 +lightbluecolor,351,12 +lightbluedye,351,12 +lbluecolour,351,12 +lbluecolor,351,12 +lbluedye,351,12 +magentacolour,351,13 +magentacolor,351,13 +magentadye,351,13 +orangecolour,351,14 +orangecolor,351,14 +orangedye,351,14 +bonemeal,351,15 +whitebonemeal,351,15 +whitebonemealcolour,351,15 +whitebonemealcolor,351,15 +whitebonemealdye,351,15 +bonemealwhite,351,15 +bonemealwhitecolour,351,15 +bonemealwhitecolor,351,15 +bonemealwhitedye,351,15 +whitebonem,351,15 +whitebonemcolour,351,15 +whitebonemcolor,351,15 +whitebonemdye,351,15 +bonemwhite,351,15 +bonemwhitecolour,351,15 +bonemwhitecolor,351,15 +bonemwhitedye,351,15 +bonemealcolour,351,15 +bonemealcolor,351,15 +bonemealdye,351,15 +bonem,351,15 +bonemcolour,351,15 +bonemcolor,351,15 +bonemdye,351,15 +whitecolour,351,15 +whitecolor,351,15 +whitedye,351,15 +bone,352,0 +sugar,353,0 +whitedust,353,0 +cake,354,0 +bed,355,0 +redstonerepeater,356,0 +redstonerepeat,356,0 +redstonedelayer,356,0 +redstonedelay,356,0 +redstonedioder,356,0 +redstonediode,356,0 +rstonerepeater,356,0 +rstonerepeat,356,0 +rstonedelayer,356,0 +rstonedelay,356,0 +rstonedioder,356,0 +rstonediode,356,0 +redsrepeater,356,0 +redsrepeat,356,0 +redsdelayer,356,0 +redsdelay,356,0 +redsdioder,356,0 +redsdiode,356,0 +rsrepeater,356,0 +rsrepeat,356,0 +rsdelayer,356,0 +rsdelay,356,0 +rsdioder,356,0 +rsdiode,356,0 +repeater,356,0 +repeat,356,0 +delayer,356,0 +delay,356,0 +dioder,356,0 +diode,356,0 +cookie,357,0 +chart,358,0 +map0,358,0 +map1,358,1 +map2,358,2 +map3,358,3 +map4,358,4 +map5,358,5 +map6,358,6 +map7,358,7 +map8,358,8 +map9,358,9 +map10,358,10 +map11,358,11 +map12,358,12 +map13,358,13 +map14,358,14 +map15,358,15 +shears,359,0 +shear,359,0 +sheers,359,0 +sheer,359,0 +woolcutters,359,0 +woolcutter,359,0 +cutterswool,359,0 +cutterwool,359,0 +melonslice,360,0 +mslice,360,0 +slicemelon,360,0 +watermelonslice,360,0 +greenmelonslice,360,0 +melongreenslice,360,0 +pumpkinseeds,361,0 +pseeds,361,0 +seedsp,361,0 +seedspumpkin,361,0 +pumpseeds,361,0 +seedspump,361,0 +melonseeds,362,0 +mseeds,362,0 +watermelonseeds,362,0 +greenmelonseeds,362,0 +gmelonseeds,362,0 +seedsmelon,362,0 +seedswatermelon,362,0 +rawbeef,363,0 +rawsteak,363,0 +uncookedbeef,363,0 +uncookedsteak,363,0 +cowmeat,363,0 +plainbeef,363,0 +beef,364,0 +steak,364,0 +cookedbeef,364,0 +grilledbeef,364,0 +cookedsteak,364,0 +grilledsteak,364,0 +cookedcowmeat,364,0 +rawchicken,365,0 +uncookedchicken,365,0 +plainchicken,365,0 +chickenplain,365,0 +chickenuncooked,365,0 +chickenraw,365,0 +cookedchicken,366,0 +grilledchicken,366,0 +toastedchicken,366,0 +gchicken,366,0 +bbqchicken,366,0 +friedchicken,366,0 +cchicken,366,0 +rottenflesh,367,0 +zombieflesh,367,0 +rottenmeat,367,0 +zombiemeat,367,0 +badflesh,367,0 +poisonflesh,367,0 +zombieremains,367,0 +enderpearl,368,0 +endpearl,368,0 +pearl,368,0 +epearl,368,0 +bluepearl,368,0 +endergem,368,0 +blazerod,369,0 +goldenrod,369,0 +goldrod,369,0 +blazestick,369,0 +goldstick,369,0 +brod,369,0 +grod,369,0 +bstick,369,0 +gstick,369,0 +ghasttear,370,0 +ghastdrop,370,0 +ghosttear,370,0 +ghostdrop,370,0 +gtear,370,0 +gdrop,370,0 +tear,370,0 +goldnugget,371,0 +gnugget,371,0 +goldpebble,371,0 +gpebble,371,0 +goldball,371,0 +gball,371,0 +netherstalk,372,0 +deathstalk,372,0 +hellstalk,372,0 +nstalk,372,0 +dstalk,372,0 +hstalk,372,0 +netherwarts,372,0 +netherwart,372,0 +netherplant,372,0 +nethercrop,372,0 +hellwarts,372,0 +hellwart,372,0 +hellplant,372,0 +hellcrop,372,0 +deathwarts,372,0 +deathwart,372,0 +deathplant,372,0 +deathcrop,372,0 +nwarts,372,0 +nwart,372,0 +ncrop,372,0 +nplant,372,0 +hwarts,372,0 +hwart,372,0 +hplant,372,0 +hcrop,372,0 +dwarts,372,0 +dwart,372,0 +dplant,372,0 +dcrop,372,0 +potion,373,0 +mixture,373,0 +potions,373,0 +waterbottle,373,0 +fullbottle,373,0 +watervase,373,0 +fullvase,373,0 +clearpotion,373,6 +clearpot,373,6 +clearextendedpotion,373,7 +clearexpotion,373,7 +clear2potion,373,7 +clearextendedpot,373,7 +clearexpot,373,7 +clear2pot,373,7 +diffusepotion,373,11 +diffusepot,373,11 +artlesspotion,373,13 +artlesspot,373,13 +thinpotion,373,14 +thinpot,373,14 +thinextendedpotion,373,15 +thinexpotion,373,15 +thin2potion,373,15 +thinextendedpot,373,15 +thinexpot,373,15 +thin2pot,373,15 +awkwardpotion,373,16 +awkwardpot,373,16 +bunglingpotion,373,22 +bunglingpot,373,22 +bunglingextendedpotion,373,23 +bunglingexpotion,373,23 +bungling2potion,373,23 +bunglingextendedpot,373,23 +bunglingexpot,373,23 +bungling2pot,373,23 +smoothpotion,373,27 +smoothpot,373,27 +suavepotion,373,29 +suavepot,373,29 +debonairpotion,373,30 +debonairpot,373,30 +debonairextendedpotion,373,31 +debonairexpotion,373,31 +debonair2potion,373,31 +debonairextendedpot,373,31 +debonairexpot,373,31 +debonair2pot,373,31 +thickpotion,373,32 +thickpot,373,32 +charmingpotion,373,38 +charmingpot,373,38 +charmingextendedpotion,373,39 +charmingexpotion,373,39 +charming2potion,373,39 +charmingextendedpot,373,39 +charmingexpot,373,39 +charming2pot,373,39 +refinedpotion,373,43 +refinedpot,373,43 +cordialpotion,373,45 +cordialpot,373,45 +sparklingpotion,373,46 +sparklingpot,373,46 +sparklingextendedpotion,373,47 +sparklingexpotion,373,47 +sparkling2potion,373,47 +sparklingextendedpot,373,47 +sparklingexpot,373,47 +sparkling2pot,373,47 +potentpotion,373,48 +potentpot,373,48 +rankpotion,373,54 +rankpot,373,54 +rankextendedpotion,373,55 +rankexpotion,373,55 +rank2potion,373,55 +rankextendedpot,373,55 +rankexpot,373,55 +rank2pot,373,55 +acridpotion,373,59 +acridpot,373,59 +grosspotion,373,61 +grosspot,373,61 +stinkypotion,373,62 +stinkypot,373,62 +stinkyextendedpotion,373,63 +stinkyexpotion,373,63 +stinky2potion,373,63 +stinkyextendedpot,373,63 +stinkyexpot,373,63 +stinky2pot,373,63 +mundaneextendedpotion,373,64 +mundaneexpotion,373,64 +mundane2potion,373,64 +mundaneextendedpot,373,64 +mundaneexpot,373,64 +mundane2pot,373,64 +mundanepotion,373,8192 +mundanepot,373,8192 +regenerationpotion,373,8193 +regeneratepotion,373,8193 +regenpotion,373,8193 +regenerationpot,373,8193 +regeneratepot,373,8193 +regenpot,373,8193 +rpot,373,8193 +swiftnesspotion,373,8194 +swiftpotion,373,8194 +speedpotion,373,8194 +swiftnesspot,373,8194 +swiftpot,373,8194 +speedpot,373,8194 +swpot,373,8194 +fireresistancepotion,373,8195 +fireresistpotion,373,8195 +firerespotion,373,8195 +fireresistancepot,373,8195 +fireresistpot,373,8195 +firerespot,373,8195 +fpot,373,8195 +poisonpotion,373,8196 +acidpotion,373,8196 +poisonpot,373,8196 +acidpot,373,8196 +ppot,373,8196 +healingpotion,373,8197 +healpotion,373,8197 +lifepotion,373,8197 +healingpot,373,8197 +healpot,373,8197 +lifepot,373,8197 +hpot,373,8197 +nightvisionpotion,373,8198 +nvisionpotion,373,8198 +nightvpotion,373,8198 +darkvisionpotion,373,8198 +dvisionpotion,373,8198 +darkvpotion,373,8198 +nightvisionpot,373,8198 +nvisionpot,373,8198 +nightvpot,373,8198 +darkvisionpot,373,8198 +dvisionpot,373,8198 +darkvpot,373,8198 +npot,373,8198 +weaknesspotion,373,8200 +weakpotion,373,8200 +weaknesspot,373,8200 +weakpot,373,8200 +wpot,373,8200 +strengthpotion,373,8201 +strongpotion,373,8201 +strpotion,373,8201 +strengthpot,373,8201 +strongpot,373,8201 +strpot,373,8201 +stpot,373,8201 +slownesspotion,373,8202 +slowpotion,373,8202 +slownesspot,373,8202 +slowpot,373,8202 +slpot,373,8202 +harmingpotion,373,8204 +damagepotion,373,8204 +dmgpotion,373,8204 +harmingpot,373,8204 +damagepot,373,8204 +dmgpot,373,8204 +dpot,373,8204 +waterbreathingpotion,373,8205 +waterbreathpotion,373,8205 +breathingpotion,373,8205 +breathpotion,373,8205 +waterbreathingpot,373,8205 +waterbreathpot,373,8205 +breathingpot,373,8205 +breathpot,373,8205 +wbpot,373,8205 +invisibilitypotion,373,8206 +invisiblepotion,373,8206 +invpotion,373,8206 +invisibilitypot,373,8206 +invisiblepot,373,8206 +invpot,373,8206 +ipot,373,8206 +regenerationleveliipotion,373,8225 +regenerateleveliipotion,373,8225 +regenleveliipotion,373,8225 +regenerationlevel2potion,373,8225 +regeneratelevel2potion,373,8225 +regenlevel2potion,373,8225 +regenerationiipotion,373,8225 +regenerateiipotion,373,8225 +regeniipotion,373,8225 +regenerationleveliipot,373,8225 +regenerateleveliipot,373,8225 +regenleveliipot,373,8225 +regenerationlevel2pot,373,8225 +regeneratelevel2pot,373,8225 +regenlevel2pot,373,8225 +regenerationiipot,373,8225 +regenerateiipot,373,8225 +regeniipot,373,8225 +r2pot,373,8225 +swiftnessleveliipotion,373,8226 +swiftleveliipotion,373,8226 +speedleveliipotion,373,8226 +swiftnesslevel2potion,373,8226 +swiftlevel2potion,373,8226 +speedlevel2potion,373,8226 +swiftnessiipotion,373,8226 +swiftiipotion,373,8226 +speediipotion,373,8226 +swiftnessleveliipot,373,8226 +swiftleveliipot,373,8226 +speedleveliipot,373,8226 +swiftnesslevel2pot,373,8226 +swiftlevel2pot,373,8226 +speedlevel2pot,373,8226 +swiftnessiipot,373,8226 +swiftiipot,373,8226 +speediipot,373,8226 +sw2pot,373,8226 +poisonleveliipotion,373,8228 +acidleveliipotion,373,8228 +poisonlevel2potion,373,8228 +acidlevel2potion,373,8228 +poisoniipotion,373,8228 +acidiipotion,373,8228 +poisonleveliipot,373,8228 +acidleveliipot,373,8228 +poisonlevel2pot,373,8228 +acidlevel2pot,373,8228 +poisoniipot,373,8228 +acidiipot,373,8228 +p2pot,373,8228 +healingleveliipotion,373,8229 +healleveliipotion,373,8229 +healinglevel2potion,373,8229 +heallevel2potion,373,8229 +healingiipotion,373,8229 +healiipotion,373,8229 +healingleveliipot,373,8229 +healleveliipot,373,8229 +healinglevel2pot,373,8229 +heallevel2pot,373,8229 +healingiipot,373,8229 +healiipot,373,8229 +h2pot,373,8229 +strengthleveliipotion,373,8233 +strongleveliipotion,373,8233 +strleveliipotion,373,8233 +strengthlevel2potion,373,8233 +stronglevel2potion,373,8233 +strlevel2potion,373,8233 +strengthiipotion,373,8233 +strongiipotion,373,8233 +striipotion,373,8233 +strengthleveliipot,373,8233 +strongleveliipot,373,8233 +strleveliipot,373,8233 +strengthlevel2pot,373,8233 +stronglevel2pot,373,8233 +strlevel2pot,373,8233 +strengthiipot,373,8233 +strongiipot,373,8233 +striipot,373,8233 +st2pot,373,8233 +harmingleveliipotion,373,8236 +damageleveliipotion,373,8236 +dmgleveliipotion,373,8236 +harminglevel2potion,373,8236 +damagelevel2potion,373,8236 +dmglevel2potion,373,8236 +harmingiipotion,373,8236 +damageiipotion,373,8236 +dmgiipotion,373,8236 +harmingleveliipot,373,8236 +damageleveliipot,373,8236 +dmgleveliipot,373,8236 +harminglevel2pot,373,8236 +damagelevel2pot,373,8236 +dmglevel2pot,373,8236 +harmingiipot,373,8236 +damageiipot,373,8236 +dmgiipot,373,8236 +d2pot,373,8236 +regenerationextendedpotion,373,8257 +regenerateextendedpotion,373,8257 +regenextendepotion,373,8257 +regenerationexpotion,373,8257 +regenerateexpotion,373,8257 +regenexpotion,373,8257 +regenerationextendedpot,373,8257 +regenerateextendedpot,373,8257 +regenextendepot,373,8257 +regenerationexpot,373,8257 +regenerateexpot,373,8257 +regenexpot,373,8257 +repot,373,8257 +swiftnessextendedpotion,373,8258 +swiftextendedpotion,373,8258 +speedextendedpotion,373,8258 +swiftnessexpotion,373,8258 +swiftexpotion,373,8258 +speedexpotion,373,8258 +swiftnessextendedpot,373,8258 +swiftextendedpot,373,8258 +speedextendedpot,373,8258 +swiftnessexpot,373,8258 +swiftexpot,373,8258 +speedexpot,373,8258 +swepot,373,8258 +fireresistanceextendedpotion,373,8259 +fireresistextendedpotion,373,8259 +fireresextendedpotion,373,8259 +fireresistanceexpotion,373,8259 +fireresistexpotion,373,8259 +fireresexpotion,373,8259 +fireresistanceextendedpot,373,8259 +fireresistextendedpot,373,8259 +fireresextendedpot,373,8259 +fireresistanceexpot,373,8259 +fireresistexpot,373,8259 +fireresexpot,373,8259 +fepot,373,8259 +poisonextendedpotion,373,8260 +acidextendedpotion,373,8260 +poisonexpotion,373,8260 +acidexpotion,373,8260 +poisonextendedpot,373,8260 +acidextendedpot,373,8260 +poisonexpot,373,8260 +acidexpot,373,8260 +pepot,373,8260 +nightvisionextendedpotion,373,8262 +nvisionextendedpotion,373,8262 +nightvextendedpotion,373,8262 +darkvisionextendedpotion,373,8262 +dvisionextendedpotion,373,8262 +darkvextendedpotion,373,8262 +nightvisionexpotion,373,8262 +nvisionexpotion,373,8262 +nightvexpotion,373,8262 +darkvisionexpotion,373,8262 +dvisionexpotion,373,8262 +darkvexpotion,373,8262 +nightvisionextendedpot,373,8262 +nvisionextendedpot,373,8262 +nightvextendedpot,373,8262 +darkvisionextendedpot,373,8262 +dvisionextendedpot,373,8262 +darkvextendedpot,373,8262 +nightvisionexpot,373,8262 +nvisionexpot,373,8262 +nightvexpot,373,8262 +darkvisionexpot,373,8262 +dvisionexpot,373,8262 +darkvexpot,373,8262 +nepot,373,8262 +weaknessextendedpotion,373,8264 +weakextendedpotion,373,8264 +weaknessexpotion,373,8264 +weakexpotion,373,8264 +weaknessextendedpot,373,8264 +weakextendedpot,373,8264 +weaknessexpot,373,8264 +weakexpot,373,8264 +wepot,373,8264 +strengthextendedpotion,373,8265 +strongextendedpotion,373,8265 +strextendedpotion,373,8265 +strengthexpotion,373,8265 +strongexpotion,373,8265 +strexpotion,373,8265 +strengthextendedpot,373,8265 +strongextendedpot,373,8265 +strextendedpot,373,8265 +strengthexpot,373,8265 +strongexpot,373,8265 +strexpot,373,8265 +stepot,373,8265 +slownessextendedpotion,373,8266 +slowextenedpotion,373,8266 +slownessexpotion,373,8266 +slowexpotion,373,8266 +slownessextendedpot,373,8266 +slowextenedpot,373,8266 +slownessexpot,373,8266 +slowexpot,373,8266 +slepot,373,8266 +waterbreathingextendedpotion,373,8269 +waterbreathextendedpotion,373,8269 +breathingextendedpotion,373,8269 +breathextendedpotion,373,8269 +waterbreathingextendedpot,373,8269 +waterbreathextendedpot,373,8269 +breathingextendedpot,373,8269 +breathextendedpot,373,8269 +waterbreathingexpotion,373,8269 +waterbreathexpotion,373,8269 +breathingexpotion,373,8269 +breathexpotion,373,8269 +waterbreathingexpot,373,8269 +waterbreathexpot,373,8269 +breathingexpot,373,8269 +breathexpot,373,8269 +wbepot,373,8269 +invisibilityextendedpotion,373,8270 +invisibleextendedpotion,373,8270 +invextendedpotion,373,8270 +invisibilityexpotion,373,8270 +invisibleexpotion,373,8270 +invexpotion,373,8270 +invisibilityextendedpot,373,8270 +invisibleextendedpot,373,8270 +invextendedpot,373,8270 +invisibilityexpot,373,8270 +invisibleexpot,373,8270 +invexpot,373,8270 +iepot,373,8270 +regenerationdualbitpotion,373,8289 +regeneratedualbitpotion,373,8289 +regendualbitpotion,373,8289 +regenerationdbpotion,373,8289 +regeneratedbpotion,373,8289 +regendbpotion,373,8289 +regenerationdualbitpot,373,8289 +regeneratedualbitpot,373,8289 +regendualbitpot,373,8289 +regenerationdbpot,373,8289 +regeneratedbpot,373,8289 +regendbpot,373,8289 +rdbpot,373,8289 +swiftnessdualbitpotion,373,8290 +swiftdualbitpotion,373,8290 +speeddualbitpotion,373,8290 +swiftnessdualbitpot,373,8290 +swiftdualbitpot,373,8290 +speeddualbitpot,373,8290 +swiftnessdbpotion,373,8290 +swiftdbpotion,373,8290 +speeddbpotion,373,8290 +swiftnessdbpot,373,8290 +swiftdbpot,373,8290 +speeddbpot,373,8290 +swdbpot,373,8290 +poisondualbitpotion,373,8292 +aciddualbitpotion,373,8292 +poisondualbitpot,373,8292 +aciddualbitpot,373,8292 +poisondbpotion,373,8292 +aciddbpotion,373,8292 +poisondbpot,373,8292 +aciddbpot,373,8292 +pdbpot,373,8292 +strengthdualbitpotion,373,8297 +strongdualbitpotion,373,8297 +strdualbitpotion,373,8297 +strengthdualbitpot,373,8297 +strongdualbitpot,373,8297 +strdualbitpot,373,8297 +strengthdbpotion,373,8297 +strongdbpotion,373,8297 +strdbpotion,373,8297 +strengthdbpot,373,8297 +strongdbpot,373,8297 +strdbpot,373,8297 +stdbpot,373,8297 +splashmundanepotion,373,16384 +splmundanepotion,373,16384 +splashregenerationpotion,373,16385 +splashregeneratepotion,373,16385 +splashregenpotion,373,16385 +splashregenerationpot,373,16385 +splashregeneratepot,373,16385 +splashregenpot,373,16385 +regenerationsplashpotion,373,16385 +regeneratesplashpotion,373,16385 +regensplashpotion,373,16385 +splregenerationpotion,373,16385 +splregeneratepotion,373,16385 +splregenpotion,373,16385 +splregenerationpot,373,16385 +splregeneratepot,373,16385 +splregenpot,373,16385 +sprpot,373,16385 +splashswiftnesspotion,373,16386 +splashswiftpotion,373,16386 +splashspeedpotion,373,16386 +splashswiftnesspot,373,16386 +splashswiftpot,373,16386 +splashspeedpot,373,16386 +splswiftnesspotion,373,16386 +splswiftpotion,373,16386 +splspeedpotion,373,16386 +splswiftnesspot,373,16386 +splswiftpot,373,16386 +splspeedpot,373,16386 +spswpot,373,16386 +splashfireresistancepotion,373,16387 +splashfireresistpotion,373,16387 +splashfirerespotion,373,16387 +splashfireresistancepot,373,16387 +splashfireresistpot,373,16387 +splashfirerespot,373,16387 +splfireresistancepotion,373,16387 +splfireresistpotion,373,16387 +splfirerespotion,373,16387 +splfireresistancepot,373,16387 +splfireresistpot,373,16387 +splfirerespot,373,16387 +spfpot,373,16387 +splashpoisonpotion,373,16388 +splashacidpotion,373,16388 +splashpoisonpot,373,16388 +splashacidpot,373,16388 +splpoisonpotion,373,16388 +splacidpotion,373,16388 +splpoisonpot,373,16388 +splacidpot,373,16388 +spppot,373,16388 +splashhealingpotion,373,16389 +splashhealpotion,373,16389 +splashlifepotion,373,16389 +splashhealingpot,373,16389 +splashhealpot,373,16389 +splashlifepot,373,16389 +splhealingpotion,373,16389 +splhealpotion,373,16389 +spllifepotion,373,16389 +splhealingpot,373,16389 +splhealpot,373,16389 +spllifepot,373,16389 +sphpot,373,16389 +splashclearpotion,373,16390 +splashclearpot,373,16390 +splclearpotion,373,16390 +splclearpot,373,16390 +splashnightvisionpotion,373,16390 +splashnvisionpotion,373,16390 +splashnightvpotion,373,16390 +splashdarkvisionpotion,373,16390 +splashdvisionpotion,373,16390 +splashdarkvpotion,373,16390 +splashnightvisionpot,373,16390 +splashnvisionpot,373,16390 +splashnightvpot,373,16390 +splashdarkvisionpot,373,16390 +splashdvisionpot,373,16390 +splashdarkvpot,373,16390 +splnightvisionpotion,373,16390 +splnvisionpotion,373,16390 +splnightvpotion,373,16390 +spldarkvisionpotion,373,16390 +spldvisionpotion,373,16390 +spldarkvpotion,373,16390 +splnightvisionpot,373,16390 +splnvisionpot,373,16390 +splnightvpot,373,16390 +spldarkvisionpot,373,16390 +spldvisionpot,373,16390 +spldarkvpot,373,16390 +spnpot,373,16390 +splashclearextendedpotion,373,16391 +splashclearexpotion,373,16391 +splashclear2potion,373,16391 +splashclearextendedpot,373,16391 +splashclearexpot,373,16391 +splashclear2pot,373,16391 +splclearextendedpotion,373,16391 +splclearexpotion,373,16391 +splclear2potion,373,16391 +splclearextendedpot,373,16391 +splclearexpot,373,16391 +splclear2pot,373,16391 +splashweaknesspotion,373,16392 +splashweakpotion,373,16392 +splashweaknesspot,373,16392 +splashweakpot,373,16392 +splweaknesspotion,373,16392 +splweakpotion,373,16392 +splweaknesspot,373,16392 +splweakpot,373,16392 +spwpot,373,16392 +splashstrengthpotion,373,16393 +splashstrongpotion,373,16393 +splashstrpotion,373,16393 +splashstrengthpot,373,16393 +splashstrongpot,373,16393 +splashstrpot,373,16393 +splstrengthpotion,373,16393 +splstrongpotion,373,16393 +splstrpotion,373,16393 +splstrengthpot,373,16393 +splstrongpot,373,16393 +splstrpot,373,16393 +spstpot,373,16393 +splashslownesspotion,373,16394 +splashslowpotion,373,16394 +splashslownesspot,373,16394 +splashslowpot,373,16394 +splslownesspotion,373,16394 +splslowpotion,373,16394 +splslownesspot,373,16394 +splslowpot,373,16394 +spslpot,373,16394 +splashdiffusepotion,373,16395 +splashdiffusepot,373,16395 +spldiffusepotion,373,16395 +spldiffusepot,373,16395 +splashharmingpotion,373,16396 +splashdamagepotion,373,16396 +splashdmgpotion,373,16396 +splashharmingpot,373,16396 +splashdamagepot,373,16396 +splashdmgpot,373,16396 +splharmingpotion,373,16396 +spldamagepotion,373,16396 +spldmgpotion,373,16396 +splharmingpot,373,16396 +spldamagepot,373,16396 +spldmgpot,373,16396 +spdpot,373,16396 +splashartlesspotion,373,16397 +splashartlesspot,373,16397 +splartlesspotion,373,16397 +splartlesspot,373,16397 +splashwaterbreathingpotion,373,16397 +splashwaterbreathpotion,373,16397 +splashbreathingpotion,373,16397 +splashbreathpotion,373,16397 +splashwaterbreathingpot,373,16397 +splashwaterbreathpot,373,16397 +splashbreathingpot,373,16397 +splashbreathpot,373,16397 +splwaterbreathingpotion,373,16397 +splwaterbreathpotion,373,16397 +splbreathingpotion,373,16397 +splbreathpotion,373,16397 +splwaterbreathingpot,373,16397 +splwaterbreathpot,373,16397 +splbreathingpot,373,16397 +splbreathpot,373,16397 +spwbpot,373,16397 +splashthinpotion,373,16398 +splashthinpot,373,16398 +splthinpotion,373,16398 +splthinpot,373,16398 +splashinvisibilitypotion,373,16398 +splashinvisiblepotion,373,16398 +splashinvpotion,373,16398 +splashinvisibilitypot,373,16398 +splashinvisiblepot,373,16398 +splashinvpot,373,16398 +splinvisibilitypotion,373,16398 +splinvisiblepotion,373,16398 +splinvpotion,373,16398 +splinvisibilitypot,373,16398 +splinvisiblepot,373,16398 +splinvpot,373,16398 +spipot,373,16398 +splashthinextendedpotion,373,16399 +splashthinexpotion,373,16399 +splashthin2potion,373,16399 +splashthinextendedpot,373,16399 +splashthinexpot,373,16399 +splashthin2pot,373,16399 +splthinextendedpotion,373,16399 +splthinexpotion,373,16399 +splthin2potion,373,16399 +splthinextendedpot,373,16399 +splthinexpot,373,16399 +splthin2pot,373,16399 +splashawkwardpotion,373,16400 +splashawkwardpot,373,16400 +splawkwardpotion,373,16400 +splawkwardpot,373,16400 +splashbunglingpotion,373,16406 +splashbunglingpot,373,16406 +splbunglingpotion,373,16406 +splbunglingpot,373,16406 +splashbunglingextendedpotion,373,16407 +splashbunglingexpotion,373,16407 +splashbungling2potion,373,16407 +splashbunglingextendedpot,373,16407 +splashbunglingexpot,373,16407 +splashbungling2pot,373,16407 +splbunglingextendedpotion,373,16407 +splbunglingexpotion,373,16407 +splbungling2potion,373,16407 +splbunglingextendedpot,373,16407 +splbunglingexpot,373,16407 +splbungling2pot,373,16407 +splashsmoothpotion,373,16411 +splashsmoothpot,373,16411 +splsmoothpotion,373,16411 +splsmoothpot,373,16411 +splashsuavepotion,373,16413 +splashsuavepot,373,16413 +splsuavepotion,373,16413 +splsuavepot,373,16413 +splashdebonairpotion,373,16414 +splashdebonairpot,373,16414 +spldebonairpotion,373,16414 +spldebonairpot,373,16414 +splashdebonairextendedpotion,373,16415 +splashdebonairexpotion,373,16415 +splashdebonair2potion,373,16415 +splashdebonairextendedpot,373,16415 +splashdebonairexpot,373,16415 +splashdebonair2pot,373,16415 +spldebonairextendedpotion,373,16415 +spldebonairexpotion,373,16415 +spldebonair2potion,373,16415 +spldebonairextendedpot,373,16415 +spldebonairexpot,373,16415 +spldebonair2pot,373,16415 +splashthickpotion,373,16416 +splashthickpot,373,16416 +splthickpotion,373,16416 +splthickpot,373,16416 +splashregenerationleveliipotion,373,16417 +splashregenerateleveliipotion,373,16417 +splashregenleveliipotion,373,16417 +splashregenerationlevel2potion,373,16417 +splashregeneratelevel2potion,373,16417 +splashregenlevel2potion,373,16417 +splashregenerationiipotion,373,16417 +splashregenerateiipotion,373,16417 +splashregeniipotion,373,16417 +splashregenerationleveliipot,373,16417 +splashregenerateleveliipot,373,16417 +splashregenleveliipot,373,16417 +splashregenerationlevel2pot,373,16417 +splashregeneratelevel2pot,373,16417 +splashregenlevel2pot,373,16417 +splashregenerationiipot,373,16417 +splashregenerateiipot,373,16417 +splashregeniipot,373,16417 +splregenerationleveliipotion,373,16417 +splregenerateleveliipotion,373,16417 +splregenleveliipotion,373,16417 +splregenerationlevel2potion,373,16417 +splregeneratelevel2potion,373,16417 +splregenlevel2potion,373,16417 +splregenerationiipotion,373,16417 +splregenerateiipotion,373,16417 +splregeniipotion,373,16417 +splregenerationleveliipot,373,16417 +splregenerateleveliipot,373,16417 +splregenleveliipot,373,16417 +splregenerationlevel2pot,373,16417 +splregeneratelevel2pot,373,16417 +splregenlevel2pot,373,16417 +splregenerationiipot,373,16417 +splregenerateiipot,373,16417 +splregeniipot,373,16417 +spr2pot,373,16417 +splashswiftnessleveliipotion,373,16418 +splashswiftleveliipotion,373,16418 +splashspeedleveliipotion,373,16418 +splashswiftnesslevel2potion,373,16418 +splashswiftlevel2potion,373,16418 +splashspeedlevel2potion,373,16418 +splashswiftnessiipotion,373,16418 +splashswiftiipotion,373,16418 +splashspeediipotion,373,16418 +splashswiftnessleveliipot,373,16418 +splashswiftleveliipot,373,16418 +splashspeedleveliipot,373,16418 +splashswiftnesslevel2pot,373,16418 +splashswiftlevel2pot,373,16418 +splashspeedlevel2pot,373,16418 +splashswiftnessiipot,373,16418 +splashswiftiipot,373,16418 +splashspeediipot,373,16418 +splswiftnessleveliipotion,373,16418 +splswiftleveliipotion,373,16418 +splspeedleveliipotion,373,16418 +splswiftnesslevel2potion,373,16418 +splswiftlevel2potion,373,16418 +splspeedlevel2potion,373,16418 +splswiftnessiipotion,373,16418 +splswiftiipotion,373,16418 +splspeediipotion,373,16418 +splswiftnessleveliipot,373,16418 +splswiftleveliipot,373,16418 +splspeedleveliipot,373,16418 +splswiftnesslevel2pot,373,16418 +splswiftlevel2pot,373,16418 +splspeedlevel2pot,373,16418 +splswiftnessiipot,373,16418 +splswiftiipot,373,16418 +splspeediipot,373,16418 +spsw2pot,373,16418 +splashpoisonleveliipotion,373,16420 +splashacidleveliipotion,373,16420 +splashpoisonlevel2potion,373,16420 +splashacidlevel2potion,373,16420 +splashpoisoniipotion,373,16420 +splashacidiipotion,373,16420 +splashpoisonleveliipot,373,16420 +splashacidleveliipot,373,16420 +splashpoisonlevel2pot,373,16420 +splashacidlevel2pot,373,16420 +splashpoisoniipot,373,16420 +splashacidiipot,373,16420 +splpoisonleveliipotion,373,16420 +splacidleveliipotion,373,16420 +splpoisonlevel2potion,373,16420 +splcidlevel2potion,373,16420 +splpoisoniipotion,373,16420 +splacidiipotion,373,16420 +splpoisonleveliipot,373,16420 +splacidleveliipot,373,16420 +splpoisonlevel2pot,373,16420 +splacidlevel2pot,373,16420 +splpoisoniipot,373,16420 +splacidiipot,373,16420 +spp2pot,373,16420 +splashhealingleveliipotion,373,16421 +splashhealleveliipotion,373,16421 +splashhealinglevel2potion,373,16421 +splashheallevel2potion,373,16421 +splashhealingiipotion,373,16421 +splashhealiipotion,373,16421 +splashhealingleveliipot,373,16421 +splashhealleveliipot,373,16421 +splashhealinglevel2pot,373,16421 +splashheallevel2pot,373,16421 +splashhealingiipot,373,16421 +splashhealiipot,373,16421 +splhealingleveliipotion,373,16421 +splhealleveliipotion,373,16421 +splhealinglevel2potion,373,16421 +splheallevel2potion,373,16421 +splhealingiipotion,373,16421 +splhealiipotion,373,16421 +splhealingleveliipot,373,16421 +splhealleveliipot,373,16421 +splhealinglevel2pot,373,16421 +splheallevel2pot,373,16421 +splhealingiipot,373,16421 +splhealiipot,373,16421 +sph2pot,373,16421 +splashcharmingpotion,373,16422 +splashcharmingpot,373,16422 +splcharmingpotion,373,16422 +splcharmingpot,373,16422 +splashcharmingextendedpotion,373,16423 +splashcharmingexpotion,373,16423 +splashcharming2potion,373,16423 +splashcharmingextendedpot,373,16423 +splashcharmingexpot,373,16423 +splashcharming2pot,373,16423 +splcharmingextendedpotion,373,16423 +splcharmingexpotion,373,16423 +splcharming2potion,373,16423 +splcharmingextendedpot,373,16423 +splcharmingexpot,373,16423 +splcharming2pot,373,16423 +splashstrengthleveliipotion,373,16425 +splashstrongleveliipotion,373,16425 +splashstrleveliipotion,373,16425 +splashstrengthlevel2potion,373,16425 +splashstronglevel2potion,373,16425 +splashstrlevel2potion,373,16425 +splashstrengthiipotion,373,16425 +splashstrongiipotion,373,16425 +splashstriipotion,373,16425 +splashstrengthleveliipot,373,16425 +splashstrongleveliipot,373,16425 +splashstrleveliipot,373,16425 +splashstrengthlevel2pot,373,16425 +splashstronglevel2pot,373,16425 +splashstrlevel2pot,373,16425 +splashstrengthiipot,373,16425 +splashstrongiipot,373,16425 +splashstriipot,373,16425 +splstrengthleveliipotion,373,16425 +splstrongleveliipotion,373,16425 +splstrleveliipotion,373,16425 +splstrengthlevel2potion,373,16425 +splstronglevel2potion,373,16425 +splstrlevel2potion,373,16425 +splstrengthiipotion,373,16425 +splstrongiipotion,373,16425 +splstriipotion,373,16425 +splstrengthleveliipot,373,16425 +splstrongleveliipot,373,16425 +splstrleveliipot,373,16425 +splstrengthlevel2pot,373,16425 +splstronglevel2pot,373,16425 +splstrlevel2pot,373,16425 +splstrengthiipot,373,16425 +splstrongiipot,373,16425 +splstriipot,373,16425 +spst2pot,373,16425 +splashrefinedpotion,373,16427 +splashrefinedpot,373,16427 +splrefinedpotion,373,16427 +splrefinedpot,373,16427 +splashharmingleveliipotion,373,16428 +splashdamageleveliipotion,373,16428 +splashdmgleveliipotion,373,16428 +splashharminglevel2potion,373,16428 +splashdamagelevel2potion,373,16428 +splashdmglevel2potion,373,16428 +splashharmingiipotion,373,16428 +splashdamageiipotion,373,16428 +splashdmgiipotion,373,16428 +splashharmingleveliipot,373,16428 +splashdamageleveliipot,373,16428 +splashdmgleveliipot,373,16428 +splashharminglevel2pot,373,16428 +splashdamagelevel2pot,373,16428 +splashdmglevel2pot,373,16428 +splashharmingiipot,373,16428 +splashdamageiipot,373,16428 +splashdmgiipot,373,16428 +splharmingleveliipotion,373,16428 +spldamageleveliipotion,373,16428 +spldmgleveliipotion,373,16428 +splharminglevel2potion,373,16428 +spldamagelevel2potion,373,16428 +spldmglevel2potion,373,16428 +splharmingiipotion,373,16428 +spldamageiipotion,373,16428 +spldmgiipotion,373,16428 +splharmingleveliipot,373,16428 +spldamageleveliipot,373,16428 +spldmgleveliipot,373,16428 +splharminglevel2pot,373,16428 +spldamagelevel2pot,373,16428 +spldmglevel2pot,373,16428 +splharmingiipot,373,16428 +spldamageiipot,373,16428 +spldmgiipot,373,16428 +spd2pot,373,16428 +splashcordialpotion,373,16429 +splashcordialpot,373,16429 +splcordialpotion,373,16429 +splcordialpot,373,16429 +splashsparklingpotion,373,16430 +splashsparklingpot,373,16430 +splsparklingpotion,373,16430 +splsparklingpot,373,16430 +splashsparklingextendedpotion,373,16431 +splashsparklingexpotion,373,16431 +splashsparkling2potion,373,16431 +splashsparklingextendedpot,373,16431 +splashsparklingexpot,373,16431 +splashsparkling2pot,373,16431 +splsparklingextendedpotion,373,16431 +splsparklingexpotion,373,16431 +splsparkling2potion,373,16431 +splsparklingextendedpot,373,16431 +splsparklingexpot,373,16431 +splsparkling2pot,373,16431 +splashpotentpotion,373,16432 +splashpotentpot,373,16432 +splpotentpotion,373,16432 +splpotentpot,373,16432 +splashrankpotion,373,16438 +splashrankpot,373,16438 +splrankpotion,373,16438 +splrankpot,373,16438 +splashrankextendedpotion,373,16439 +splashrankexpotion,373,16439 +splashrank2potion,373,16439 +splashrankextendedpot,373,16439 +splashrankexpot,373,16439 +splashrank2pot,373,16439 +splrankextendedpotion,373,16439 +splrankexpotion,373,16439 +splrank2potion,373,16439 +splrankextendedpot,373,16439 +splrankexpot,373,16439 +splrank2pot,373,16439 +splashacridpotion,373,16443 +splashacridpot,373,16443 +splacridpotion,373,16443 +splacridpot,373,16443 +splashgrosspotion,373,16445 +splashgrosspot,373,16445 +splgrosspotion,373,16445 +splgrosspot,373,16445 +splashstinkypotion,373,16446 +splashstinkypot,373,16446 +splstinkypotion,373,16446 +splstinkypot,373,16446 +splashstinkyextendedpotion,373,16447 +splashstinkyexpotion,373,16447 +splashstinky2potion,373,16447 +splashstinkyextendedpot,373,16447 +splashstinkyexpot,373,16447 +splashstinky2pot,373,16447 +splstinkyextendedpotion,373,16447 +splstinkyexpotion,373,16447 +splstinky2potion,373,16447 +splstinkyextendedpot,373,16447 +splstinkyexpot,373,16447 +splstinky2pot,373,16447 +splashmundaneextendedpotion,373,16448 +splashmundaneexpotion,373,16448 +splashmundane2potion,373,16448 +splashmundaneextendedpot,373,16448 +splashmundaneexpot,373,16448 +splashmundane2pot,373,16448 +splmundaneextendedpotion,373,16448 +splmundaneexpotion,373,16448 +splmundane2potion,373,16448 +splmundaneextendedpot,373,16448 +splmundaneexpot,373,16448 +splmundane2pot,373,16448 +splashregenerationextendedpotion,373,16449 +splashregenerateextendedpotion,373,16449 +splashregenextendepotion,373,16449 +splashregenerationexpotion,373,16449 +splashregenerateexpotion,373,16449 +splashregenexpotion,373,16449 +splashregenerationextendedpot,373,16449 +splashregenerateextendedpot,373,16449 +splashregenextendepot,373,16449 +splashregenerationexpot,373,16449 +splashregenerateexpot,373,16449 +splashregenexpot,373,16449 +splregenerationextendedpotion,373,16449 +splregenerateextendedpotion,373,16449 +splregenextendepotion,373,16449 +splregenerationexpotion,373,16449 +splregenerateexpotion,373,16449 +splregenexpotion,373,16449 +splregenerationextendedpot,373,16449 +splregenerateextendedpot,373,16449 +splregenextendepot,373,16449 +splregenerationexpot,373,16449 +splregenerateexpot,373,16449 +splregenexpot,373,16449 +sprepot,373,16449 +splashswiftnessextendedpotion,373,16450 +splashswiftextendedpotion,373,16450 +splashspeedextendedpotion,373,16450 +splashswiftnessexpotion,373,16450 +splashswiftexpotion,373,16450 +splashspeedexpotion,373,16450 +splashswiftnessextendedpot,373,16450 +splashswiftextendedpot,373,16450 +splashspeedextendedpot,373,16450 +splashswiftnessexpot,373,16450 +splashswiftexpot,373,16450 +splashspeedexpot,373,16450 +splswiftnessextendedpotion,373,16450 +splswiftextendedpotion,373,16450 +splspeedextendedpotion,373,16450 +splswiftnessexpotion,373,16450 +splswiftexpotion,373,16450 +splspeedexpotion,373,16450 +splswiftnessextendedpot,373,16450 +splswiftextendedpot,373,16450 +splspeedextendedpot,373,16450 +splswiftnessexpot,373,16450 +splswiftexpot,373,16450 +splspeedexpot,373,16450 +spswepot,373,16450 +splashfireresistanceextendedpotion,373,16451 +splashfireresistextendedpotion,373,16451 +splashfireresextendedpotion,373,16451 +splashfireresistanceexpotion,373,16451 +splashfireresistexpotion,373,16451 +splashfireresexpotion,373,16451 +splashfireresistanceextendedpot,373,16451 +splashfireresistextendedpot,373,16451 +splashfireresextendedpot,373,16451 +splashfireresistanceexpot,373,16451 +splashfireresistexpot,373,16451 +splashfireresexpot,373,16451 +splfireresistanceextendedpotion,373,16451 +splfireresistextendedpotion,373,16451 +splfireresextendedpotion,373,16451 +splfireresistanceexpotion,373,16451 +splfireresistexpotion,373,16451 +splfireresexpotion,373,16451 +splfireresistanceextendedpot,373,16451 +splfireresistextendedpot,373,16451 +splfireresextendedpot,373,16451 +splfireresistanceexpot,373,16451 +splfireresistexpot,373,16451 +splfireresexpot,373,16451 +spfepot,373,16451 +splashpoisonextendedpotion,373,16452 +splashacidextendedpotion,373,16452 +splashpoisonexpotion,373,16452 +splashacidexpotion,373,16452 +splashpoisonextendedpot,373,16452 +splashacidextendedpot,373,16452 +splashpoisonexpot,373,16452 +splashacidexpot,373,16452 +splpoisonextendedpotion,373,16452 +splacidextendedpotion,373,16452 +splpoisonexpotion,373,16452 +splacidexpotion,373,16452 +splpoisonextendedpot,373,16452 +splacidextendedpot,373,16452 +splpoisonexpot,373,16452 +splacidexpot,373,16452 +sppepot,373,16452 +splashnightvisionextendedpotion,373,16454 +splashnvisionextendedpotion,373,16454 +splashnightvextendedpotion,373,16454 +splashdarkvisionextendedpotion,373,16454 +splashdvisionextendedpotion,373,16454 +splashdarkvextendedpotion,373,16454 +splashnightvisionextendedpot,373,16454 +splashnvisionextendedpot,373,16454 +splashnightvextendedpot,373,16454 +splashdarkvisionextendedpot,373,16454 +splashdvisionextendedpot,373,16454 +splashdarkvextendedpot,373,16454 +splashnightvisionexpotion,373,16454 +splashnvisionexpotion,373,16454 +splashnightvexpotion,373,16454 +splashdarkvisionexpotion,373,16454 +splashdvisionexpotion,373,16454 +splashdarkvexpotion,373,16454 +splashnightvisionexpot,373,16454 +splashnvisionexpot,373,16454 +splashnightvexpot,373,16454 +splashdarkvisionexpot,373,16454 +splashdvisionexpot,373,16454 +splashdarkvexpot,373,16454 +splnightvisionextendedpotion,373,16454 +splnvisionextendedpotion,373,16454 +splnightvextendedpotion,373,16454 +spldarkvisionextendedpotion,373,16454 +spldvisionextendedpotion,373,16454 +spldarkvextendedpotion,373,16454 +splnightvisionextendedpot,373,16454 +splnvisionextendedpot,373,16454 +splnightvextendedpot,373,16454 +spldarkvisionextendedpot,373,16454 +spldvisionextendedpot,373,16454 +spldarkvextendedpot,373,16454 +splnightvisionexpotion,373,16454 +splnvisionexpotion,373,16454 +splnightvexpotion,373,16454 +spldarkvisionexpotion,373,16454 +spldvisionexpotion,373,16454 +spldarkvexpotion,373,16454 +splnightvisionexpot,373,16454 +splnvisionexpot,373,16454 +splnightvexpot,373,16454 +spldarkvisionexpot,373,16454 +spldvisionexpot,373,16454 +spldarkvexpot,373,16454 +spnepot,373,16454 +splashweaknessextendedpotion,373,16456 +splashweakextendedpotion,373,16456 +splashweaknessexpotion,373,16456 +splashweakexpotion,373,16456 +splashweaknessextendedpot,373,16456 +splashweakextendedpot,373,16456 +splashweaknessexpot,373,16456 +splashweakexpot,373,16456 +splweaknessextendedpotion,373,16456 +sphweakextendedpotion,373,16456 +splweaknessexpotion,373,16456 +splweakexpotion,373,16456 +splweaknessextendedpot,373,16456 +splweakextendedpot,373,16456 +splweaknessexpot,373,16456 +splweakexpot,373,16456 +spwepot,373,16456 +splashstrengthextendedpotion,373,16457 +splashstrongextendedpotion,373,16457 +splashstrextendedpotion,373,16457 +splashstrengthexpotion,373,16457 +splashstrongexpotion,373,16457 +splashstrexpotion,373,16457 +splashstrengthextendedpot,373,16457 +splashstrongextendedpot,373,16457 +splashstrextendedpot,373,16457 +splashstrengthexpot,373,16457 +splashstrongexpot,373,16457 +splashstrexpot,373,16457 +splstrengthextendedpotion,373,16457 +splstrongextendedpotion,373,16457 +splstrextendedpotion,373,16457 +splstrengthexpotion,373,16457 +splstrongexpotion,373,16457 +splstrexpotion,373,16457 +splstrengthextendedpot,373,16457 +splstrongextendedpot,373,16457 +splstrextendedpot,373,16457 +splstrengthexpot,373,16457 +splstrongexpot,373,16457 +splstrexpot,373,16457 +spstepot,373,16457 +splashslownessextendedpotion,373,16458 +splashslowextenedpotion,373,16458 +splashslownessexpotion,373,16458 +splashslowexpotion,373,16458 +splashslownessextendedpot,373,16458 +splashslowextenedpot,373,16458 +splashslownessexpot,373,16458 +splashslowexpot,373,16458 +splslownessextendedpotion,373,16458 +splslowextenedpotion,373,16458 +splslownessexpotion,373,16458 +splslowexpotion,373,16458 +splslownessextendedpot,373,16458 +splslowextenedpot,373,16458 +splslownessexpot,373,16458 +splslowexpot,373,16458 +spslepot,373,16458 +splashwaterbreathingextendedpotion,373,16461 +splashwaterbreathextendedpotion,373,16461 +splashbreathingextendedpotion,373,16461 +splashbreathextendedpotion,373,16461 +splashwaterbreathingextendedpot,373,16461 +splashwaterbreathextendedpot,373,16461 +splashbreathingextendedpot,373,16461 +splashbreathextendedpot,373,16461 +splwaterbreathingextendedpotion,373,16461 +splwaterbreathextendedpotion,373,16461 +splbreathingextendedpotion,373,16461 +splbreathextendedpotion,373,16461 +splwaterbreathingextendedpot,373,16461 +splwaterbreathextendedpot,373,16461 +splbreathingextendedpot,373,16461 +splbreathextendedpot,373,16461 +splashwaterbreathingexpotion,373,16461 +splashwaterbreathexpotion,373,16461 +splashbreathingexpotion,373,16461 +splashbreathexpotion,373,16461 +splashwaterbreathingexpot,373,16461 +splashwaterbreathexpot,373,16461 +splashbreathingexpot,373,16461 +splashbreathexpot,373,16461 +splwaterbreathingexpotion,373,16461 +splwaterbreathexpotion,373,16461 +splbreathingexpotion,373,16461 +splbreathexpotion,373,16461 +splwaterbreathingexpot,373,16461 +splwaterbreathexpot,373,16461 +splbreathingexpot,373,16461 +splbreathexpot,373,16461 +spwbepot,373,16461 +splashinvisibilityextendedpotion,373,16462 +splashinvisibleextendedpotion,373,16462 +splashinvextendedpotion,373,16462 +splashinvisibilityextendedpot,373,16462 +splashinvisibleextendedpot,373,16462 +splashinvextendedpot,373,16462 +splashinvisibilityexpotion,373,16462 +splashinvisibleexpotion,373,16462 +splashinvexpotion,373,16462 +splashinvisibilityexpot,373,16462 +splashinvisibleexpot,373,16462 +splashinvexpot,373,16462 +splinvisibilityextendedpotion,373,16462 +splinvisibleextendedpotion,373,16462 +splinvextendedpotion,373,16462 +splinvisibilityextendedpot,373,16462 +splinvisibleextendedpot,373,16462 +splinvextendedpot,373,16462 +splinvisibilityexpotion,373,16462 +splinvisibleexpotion,373,16462 +splinvexpotion,373,16462 +splinvisibilityexpot,373,16462 +splinvisibleexpot,373,16462 +splinvexpot,373,16462 +spiepot,373,16462 +splashregenerationdualbitpotion,373,16481 +splashregeneratedualbitpotion,373,16481 +splashregendualbitpotion,373,16481 +splashregenerationdualbitpot,373,16481 +splashregeneratedualbitpot,373,16481 +splashregendualbitpot,373,16481 +splregenerationdualbitpotion,373,16481 +splregeneratedualbitpotion,373,16481 +splregendualbitpotion,373,16481 +splregenerationdualbitpot,373,16481 +splregeneratedualbitpot,373,16481 +splregendualbitpot,373,16481 +splashregenerationdbpotion,373,16481 +splashregeneratedbpotion,373,16481 +splashregendbpotion,373,16481 +splashregenerationdbpot,373,16481 +splashregeneratedbpot,373,16481 +splashregendbpot,373,16481 +splregenerationdbpotion,373,16481 +splregeneratedbpotion,373,16481 +splregendbpotion,373,16481 +splregenerationdbpot,373,16481 +splregeneratedbpot,373,16481 +splregendbpot,373,16481 +sprdbpot,373,16481 +splashswiftnessdualbitpotion,373,16482 +splashswiftdualbitpotion,373,16482 +splashspeeddualbitpotion,373,16482 +splashswiftnessdualbitpot,373,16482 +splashswiftdualbitpot,373,16482 +splashspeeddualbitpot,373,16482 +splswiftnessdualbitpotion,373,16482 +splswiftdualbitpotion,373,16482 +splspeeddualbitpotion,373,16482 +splswiftnessdualbitpot,373,16482 +splswiftdualbitpot,373,16482 +splspeeddualbitpot,373,16482 +splashswiftnessdbpotion,373,16482 +splashswiftdbpotion,373,16482 +splashspeeddbpotion,373,16482 +splashswiftnessdbpot,373,16482 +splashswiftdbpot,373,16482 +splashspeeddbpot,373,16482 +splswiftnessdbpotion,373,16482 +splswiftdbpotion,373,16482 +splspeeddbpotion,373,16482 +splswiftnessdbpot,373,16482 +splswiftdbpot,373,16482 +splspeeddbpot,373,16482 +spswdbpot,373,16482 +splashpoisondualbitpotion,373,16484 +splashaciddualbitpotion,373,16484 +splashpoisondualbitpot,373,16484 +splashaciddualbitpot,373,16484 +splpoisondualbitpotion,373,16484 +splaciddualbitpotion,373,16484 +splpoisondualbitpot,373,16484 +splaciddualbitpot,373,16484 +splashpoisondbpotion,373,16484 +splashaciddbpotion,373,16484 +splashpoisondbpot,373,16484 +splashaciddbpot,373,16484 +splpoisondbpotion,373,16484 +splaciddbpotion,373,16484 +splpoisondbpot,373,16484 +splaciddbpot,373,16484 +sppdbpot,373,16484 +splashstrengthdualbitpotion,373,16489 +splashstrongdualbitpotion,373,16489 +splashstrdualbitpotion,373,16489 +splashstrengthdualbitpot,373,16489 +splashstrongdualbitpot,373,16489 +splashstrdualbitpot,373,16489 +splstrengthdualbitpotion,373,16489 +splstrongdualbitpotion,373,16489 +splstrdualbitpotion,373,16489 +splstrengthdualbitpot,373,16489 +splstrongdualbitpot,373,16489 +splstrdualbitpot,373,16489 +splashstrengthdbpotion,373,16489 +splashstrongdbpotion,373,16489 +splashstrdbpotion,373,16489 +splashstrengthdbpot,373,16489 +splashstrongdbpot,373,16489 +splashstrdbpot,373,16489 +splstrengthdbpotion,373,16489 +splstrongdbpotion,373,16489 +splstrdbpotion,373,16489 +splstrengthdbpot,373,16489 +splstrongdbpot,373,16489 +splstrdbpot,373,16489 +spstdbpot,373,16489 +glassbottle,374,0 +bottle,374,0 +gbottle,374,0 +gvase,374,0 +vase,374,0 +glassvase,374,0 +emptyglassbottle,374,0 +emptybottle,374,0 +emptygbottle,374,0 +emptygvase,374,0 +emptyvase,374,0 +emptyglassvase,374,0 +eglassbottle,374,0 +ebottle,374,0 +egbottle,374,0 +egvase,374,0 +evase,374,0 +eglassvase,374,0 +spidereye,375,0 +eyeofspider,375,0 +seye,375,0 +fermentedspidereye,376,0 +craftedspidereye,376,0 +fspidereye,376,0 +cspidereye,376,0 +fermentedeyeofspider,376,0 +craftedeyeofspider,376,0 +feyeofspider,376,0 +ceyeofspider,376,0 +fermentedseye,376,0 +craftedseye,376,0 +fseye,376,0 +cseye,376,0 +blazepowder,377,0 +blazedust,377,0 +goldpowder,377,0 +golddust,377,0 +gdust,377,0 +gpowder,377,0 +bpowder,377,0 +bdust,377,0 +magmacream,378,0 +goldcream,378,0 +blazecream,378,0 +mcream,378,0 +gcream,378,0 +bcream,378,0 +combinedcream,378,0 +ccream,378,0 +bstand,379,0 +pstand,379,0 +brewingstand,379,0 +potionstand,379,0 +cauldron,380,0 +steelcauldron,380,0 +ironcauldron,380,0 +icauldron,380,0 +scauldron,380,0 +potioncauldron,380,0 +pcauldron,380,0 +eyeofender,381,0 +endereye,381,0 +endeye,381,0 +evilendereye,381,0 +evileyeofender,381,0 +evilenderpearl,381,0 +eeye,381,0 +eofender,381,0 +glisteringmelon,382,0 +speckledmelon,382,0 +goldmelon,382,0 +sparklymelon,382,0 +shiningmelon,382,0 +gmelon,382,0 +smelon,382,0 +creeperegg,383,50 +eggcreeper,383,50 +skeletonegg,383,51 +eggskeleton,383,51 +spideregg,383,52 +eggspider,383,52 +giantegg,383,53 +egggiant,383,53 +zombieegg,383,54 +eggzombie,383,54 +slimeegg,383,55 +eggslime,383,55 +ghastegg,383,56 +eggghast,383,56 +zombiepigmanegg,383,57 +zpigmanegg,383,57 +pigmanegg,383,57 +zombiepmanegg,383,57 +zpmanegg,383,57 +zombiepigmegg,383,57 +zpigmegg,383,57 +zombiepigegg,383,57 +zpigegg,383,57 +zombiepmegg,383,57 +zombiepegg,383,57 +eggzombiepigman,383,57 +eggzpigman,383,57 +eggpigman,383,57 +eggzombiepman,383,57 +eggzpman,383,57 +eggzombiepigm,383,57 +eggzpigm,383,57 +eggzombiepig,383,57 +eggzpig,383,57 +eggzombiepm,383,57 +eggzombiep,383,57 +endermanegg,383,58 +eggenderman,383,58 +eggcavespider,383,59 +cavespideregg,383,59 +silverfishegg,383,60 +eggsilverfish,383,60 +blazeegg,383,61 +eggblaze,383,61 +lavaslimeegg,383,62 +lavacubeegg,383,62 +magmacubeegg,383,62 +magmaslimeegg,383,62 +egglavaslime,383,62 +egglavacube,383,62 +eggmagmacube,383,62 +eggmagmaslime,383,62 +bategg,383,65 +eggbat,383,65 +witchegg,383,66 +eggwitch,383,66 +pigegg,383,90 +eggpig,383,90 +sheepegg,383,91 +eggsheep,383,91 +cowegg,383,92 +eggcow,383,92 +chickenegg,383,93 +eggchicken,383,93 +squidegg,383,94 +eggsquid,383,94 +wolfegg,383,95 +eggwolf,383,95 +mooshroomegg,383,96 +mushroomcowegg,383,96 +eggmooshroom,383,96 +eggmushroomcow,383,96 +snowgolemegg,383,97 +sgolemegg,383,97 +eggsnowgolem,383,97 +eggsgolem,383,97 +ocelotegg,383,98 +eggocelot,383,98 +irongolemegg,383,99 +igolemegg,383,99 +eggirongolem,383,99 +eggigolem,383,99 +egghorse,383,100 +horseegg,383,100 +villageregg,383,120 +eggvillager,383,120 +bottleofenchanting,384,0 +enchantingbottle,384,0 +expbottle,384,0 +xpbottle,384,0 +bottleexp,384,0 +bottlexp,384,0 +enchantbottle,384,0 +bottleenchanting,384,0 +bottleenchant,384,0 +bottleoenchanting,384,0 +firecharge,385,0 +fireball,385,0 +grenade,385,0 +bookandquill,386,0 +booknquill,386,0 +bookandfeather,386,0 +booknfeather,386,0 +writeablebook,386,0 +writtenbook,387,0 +readablebook,387,0 +sealedbook,387,0 +diary,387,0 +ownedbook,387,0 +emerald,388,0 +itemframe,389,0 +pictureframe,389,0 +iframe,389,0 +pframe,389,0 +flowerpot,390,0 +pot,390,0 +carrot,391,0 +potato,392,0 +rawpotato,392,0 +bakedpotato,393,0 +roastedpotato,393,0 +cookedpotato,393,0 +bakepotato,393,0 +roastpotato,393,0 +cookpotato,393,0 +bpotato,393,0 +rpotato,393,0 +cpotato,393,0 +poisonouspotato,394,0 +poisonpotato,394,0 +ppotato,394,0 +emptymap,395,0 +map,395,0 +goldencarrot,396,0 +goldcarrot,396,0 +gcarrot,396,0 +head,397,0 +skull,397,0 +skeletonhead,397,0 +headskeleton,397,0 +skeletonskull,397,0 +skullskeleton,397,0 +witherhead,397,1 +witherskeletonhead,397,1 +wskeletionhead,397,1 +headwither,397,1 +headwitherskeleton,397,1 +headwskeletion,397,1 +witherskull,397,1 +witherskeletonskull,397,1 +wskeletionskull,397,1 +skullwither,397,1 +skullwitherskeleton,397,1 +skullwskeletion,397,1 +zombiehead,397,2 +headzombie,397,2 +zombieskull,397,2 +skullzombie,397,2 +playerhead,397,3 +humanhead,397,3 +stevehead,397,3 +headplayer,397,3 +headhuman,397,3 +headsteve,397,3 +playerskull,397,3 +humanskull,397,3 +steveskull,397,3 +skullplayer,397,3 +skullhuman,397,3 +skullsteve,397,3 +creeperhead,397,4 +headcreeper,397,4 +creeperskull,397,4 +skullcreeper,397,4 +carrotonastick,398,0 +carrotonstick,398,0 +netherstar,399,0 +hellstar,399,0 +nstar,399,0 +hstar,399,0 +star,399,0 +pumpkinpie,400,0 +pumpkincake,400,0 +ppie,400,0 +pcake,400,0 +pie,400,0 +fireworkrocket,401,0 +fireworkmissle,401,0 +firework,401,0 +fworkrocket,401,0 +fworkmissle,401,0 +fwork,401,0 +fwrocket,401,0 +fwmissle,401,0 +fireworkstar,402,0 +fworkstar,402,0 +fwstar,402,0 +fireworkball,402,0 +fworkball,402,0 +fwball,402,0 +fireworkpowder,402,0 +fworkpowder,402,0 +fwpowder,402,0 +fireworkcharge,402,0 +fworkcharge,402,0 +fwcharge,402,0 +enchantedbook,403,0 +enchantmentbook,403,0 +enchantingbook,403,0 +enchantbook,403,0 +magicalbook,403,0 +magicbook,403,0 +ebook,403,0 +mbook,403,0 +redstonecomparator,404,0 +redstonecomparer,404,0 +redstonecompare,404,0 +rstonecomparator,404,0 +rstonecomparer,404,0 +rstonecompare,404,0 +redscomparator,404,0 +redscomparer,404,0 +redscompare,404,0 +rscomparator,404,0 +rscomparer,404,0 +rscompare,404,0 +comparator,404,0 +comparer,404,0 +compare,404,0 +netherbrick,405,0 +nbrick,405,0 +hellbrick,405,0 +deathbrick,405,0 +dbrick,405,0 +hbrick,405,0 +netherquartz,406,0 +deathquartz,406,0 +hellquartz,406,0 +nquartz,406,0 +dquartz,406,0 +hquartz,406,0 +quartz,406,0 +tntminecart,407,0 +dynamiteminecart,407,0 +dynamitemcart,407,0 +dynamitecart,407,0 +bombminecart,407,0 +bombmcart,407,0 +bombcart,407,0 +tntmcart,407,0 +tntcart,407,0 +dminecart,407,0 +dmcart,407,0 +dcart,407,0 +bminecart,407,0 +bmcart,407,0 +bcart,407,0 +tminecart,407,0 +tmcart,407,0 +tcart,407,0 +hopperminecart,408,0 +hoppermcart,408,0 +hoppercart,408,0 +hopminecart,408,0 +hopmcart,408,0 +hopcart,408,0 +hminecart,408,0 +hmcart,408,0 +hcart,408,0 +ironhorsearmor,417,0 +ironharmor,417,0 +ironarmor,417,0 +ihorsearmor,417,0 +iharmor,417,0 +iarmor,417,0 +steelhorsearmor,417,0 +steelharmor,417,0 +steelarmor,417,0 +shorsearmor,417,0 +sharmor,417,0 +sarmor,417,0 +goldenhorsearmor,418,0 +goldenharmor,418,0 +goldenarmor,418,0 +goldhorsearmor,418,0 +goldharmor,418,0 +goldarmor,418,0 +ghorsearmor,418,0 +gharmor,418,0 +garmor,418,0 +diamondhorsearmor,419,0 +diamondharmor,419,0 +diamondarmor,419,0 +dhorsearmor,419,0 +dharmor,419,0 +darmor,419,0 +crystalhorsearmor,419,0 +crystalharmor,419,0 +crystalarmor,419,0 +chorsearmor,419,0 +charmor,419,0 +carmor,419,0 +lead,420,0 +leash,420,0 +rope,420,0 +nametag,421,0 +tag,421,0 +commandblockminecart,422,0 +cmdblockminecart,422,0 +cblockminecart,422,0 +commandminecart,422,0 +cmdminecart,422,0 +cbminecart,422,0 +commandblockcart,422,0 +cmdblockcart,422,0 +cblockcart,422,0 +commandcart,422,0 +cmdcart,422,0 +cbcart,422,0 +13disc,2256,0 +goldmusicrecord,2256,0 +goldmusicdisk,2256,0 +goldmusicdisc,2256,0 +goldmusiccd,2256,0 +13musicrecord,2256,0 +13musicdisk,2256,0 +13musicdisc,2256,0 +13musiccd,2256,0 +gomusicrecord,2256,0 +gomusicdisk,2256,0 +gomusicdisc,2256,0 +gomusiccd,2256,0 +goldmrecord,2256,0 +goldmdisk,2256,0 +goldmdisc,2256,0 +goldmcd,2256,0 +13mrecord,2256,0 +13mdisk,2256,0 +13mdisc,2256,0 +13mcd,2256,0 +gomrecord,2256,0 +gomdisk,2256,0 +gomdisc,2256,0 +gomcd,2256,0 +goldrecord,2256,0 +golddisk,2256,0 +golddisc,2256,0 +goldcd,2256,0 +13record,2256,0 +13disk,2256,0 +13cd,2256,0 +gorecord,2256,0 +godisk,2256,0 +godisc,2256,0 +gocd,2256,0 +record1,2256,0 +disk1,2256,0 +disc1,2256,0 +cd1,2256,0 +1record,2256,0 +1disk,2256,0 +1disc,2256,0 +1cd,2256,0 +catdisc,2257,0 +greenmusicrecord,2257,0 +greenmusicdisk,2257,0 +greenmusicdisc,2257,0 +greenmusiccd,2257,0 +catmusicrecord,2257,0 +catmusicdisk,2257,0 +catmusicdisc,2257,0 +catmusiccd,2257,0 +grmusicrecord,2257,0 +grmusicdisk,2257,0 +grmusicdisc,2257,0 +grmusiccd,2257,0 +greenmrecord,2257,0 +greenmdisk,2257,0 +greenmdisc,2257,0 +greenmcd,2257,0 +catmrecord,2257,0 +catmdisk,2257,0 +catmdisc,2257,0 +catmcd,2257,0 +grmrecord,2257,0 +grmdisk,2257,0 +grmdisc,2257,0 +grmcd,2257,0 +greenrecord,2257,0 +greendisk,2257,0 +greendisc,2257,0 +greencd,2257,0 +catrecord,2257,0 +catdisk,2257,0 +catcd,2257,0 +grrecord,2257,0 +grdisk,2257,0 +grdisc,2257,0 +grcd,2257,0 +record2,2257,0 +disk2,2257,0 +disc2,2257,0 +cd2,2257,0 +2record,2257,0 +2disk,2257,0 +2disc,2257,0 +2cd,2257,0 +blocksdisc,2258,0 +orangemusicrecord,2258,0 +orangemusicdisk,2258,0 +orangemusicdisc,2258,0 +orangemusiccd,2258,0 +blocksmusicrecord,2258,0 +blocksmusicdisk,2258,0 +blocksmusicdisc,2258,0 +blocksmusiccd,2258,0 +ormusicrecord,2258,0 +ormusicdisk,2258,0 +ormusicdisc,2258,0 +ormusiccd,2258,0 +orangemrecord,2258,0 +orangemdisk,2258,0 +orangemdisc,2258,0 +orangemcd,2258,0 +blocksmrecord,2258,0 +blocksmdisk,2258,0 +blocksmdisc,2258,0 +blocksmcd,2258,0 +ormrecord,2258,0 +ormdisk,2258,0 +ormdisc,2258,0 +ormcd,2258,0 +orangerecord,2258,0 +orangedisk,2258,0 +orangedisc,2258,0 +orangecd,2258,0 +blocksrecord,2258,0 +blocksdisk,2258,0 +blockscd,2258,0 +orrecord,2258,0 +ordisk,2258,0 +ordisc,2258,0 +orcd,2258,0 +record3,2258,0 +disk3,2258,0 +disc3,2258,0 +cd3,2258,0 +3record,2258,0 +3disk,2258,0 +3disc,2258,0 +3cd,2258,0 +chirpdisc,2259,0 +redmusicrecord,2259,0 +redmusicdisk,2259,0 +redmusicdisc,2259,0 +redmusiccd,2259,0 +chirpmusicrecord,2259,0 +chirpmusicdisk,2259,0 +chirpmusicdisc,2259,0 +chirpmusiccd,2259,0 +remusicrecord,2259,0 +remusicdisk,2259,0 +remusicdisc,2259,0 +remusiccd,2259,0 +redmrecord,2259,0 +redmdisk,2259,0 +redmdisc,2259,0 +redmcd,2259,0 +chirpmrecord,2259,0 +chirpmdisk,2259,0 +chirpmdisc,2259,0 +chirpmcd,2259,0 +remrecord,2259,0 +remdisk,2259,0 +remdisc,2259,0 +remcd,2259,0 +redrecord,2259,0 +reddisk,2259,0 +reddisc,2259,0 +redcd,2259,0 +chirprecord,2259,0 +chirpdisk,2259,0 +chirpcd,2259,0 +rerecord,2259,0 +redisk,2259,0 +redisc,2259,0 +recd,2259,0 +record4,2259,0 +disk4,2259,0 +disc4,2259,0 +cd4,2259,0 +4record,2259,0 +4disk,2259,0 +4disc,2259,0 +4cd,2259,0 +fardisc,2260,0 +lightgreenmusicrecord,2260,0 +lightgreenmusicdisk,2260,0 +lightgreenmusicdisc,2260,0 +lightgreenmusiccd,2260,0 +lgreenmusicrecord,2260,0 +lgreenmusicdisk,2260,0 +lgreenmusicdisc,2260,0 +lgreenmusiccd,2260,0 +lightgrmusicrecord,2260,0 +lightgrmusicdisk,2260,0 +lightgrmusicdisc,2260,0 +lightgrmusiccd,2260,0 +farmusicrecord,2260,0 +farmusicdisk,2260,0 +farmusicdisc,2260,0 +farmusiccd,2260,0 +lgrmusicrecord,2260,0 +lgrmusicdisk,2260,0 +lgrmusicdisc,2260,0 +lgrmusiccd,2260,0 +lightgreenmrecord,2260,0 +lightgreenmdisk,2260,0 +lightgreenmdisc,2260,0 +lightgreenmcd,2260,0 +lgreenmrecord,2260,0 +lgreenmdisk,2260,0 +lgreenmdisc,2260,0 +lgreenmcd,2260,0 +lightgrmrecord,2260,0 +lightgrmdisk,2260,0 +lightgrmdisc,2260,0 +lightgrmcd,2260,0 +farmrecord,2260,0 +farmdisk,2260,0 +farmdisc,2260,0 +farmcd,2260,0 +lgrmrecord,2260,0 +lgrmdisk,2260,0 +lgrmdisc,2260,0 +lgrmcd,2260,0 +lightgreenrecord,2260,0 +lightgreendisk,2260,0 +lightgreendisc,2260,0 +lightgreencd,2260,0 +lgreenrecord,2260,0 +lgreendisk,2260,0 +lgreendisc,2260,0 +lgreencd,2260,0 +lightgrrecord,2260,0 +lightgrdisk,2260,0 +lightgrdisc,2260,0 +lightgrcd,2260,0 +farrecord,2260,0 +fardisk,2260,0 +farcd,2260,0 +lgrrecord,2260,0 +lgrdisk,2260,0 +lgrdisc,2260,0 +lgrcd,2260,0 +record5,2260,0 +disk5,2260,0 +disc5,2260,0 +cd5,2260,0 +5record,2260,0 +5disk,2260,0 +5disc,2260,0 +5cd,2260,0 +malldisc,2261,0 +purplemusicrecord,2261,0 +purplemusicdisk,2261,0 +purplemusicdisc,2261,0 +purplemusiccd,2261,0 +mallmusicrecord,2261,0 +mallmusicdisk,2261,0 +mallmusicdisc,2261,0 +mallmusiccd,2261,0 +pumusicrecord,2261,0 +pumusicdisk,2261,0 +pumusicdisc,2261,0 +pumusiccd,2261,0 +purplemrecord,2261,0 +purplemdisk,2261,0 +purplemdisc,2261,0 +purplemcd,2261,0 +mallmrecord,2261,0 +mallmdisk,2261,0 +mallmdisc,2261,0 +mallmcd,2261,0 +pumrecord,2261,0 +pumdisk,2261,0 +pumdisc,2261,0 +pumcd,2261,0 +purplerecord,2261,0 +purpledisk,2261,0 +purpledisc,2261,0 +purplecd,2261,0 +mallrecord,2261,0 +malldisk,2261,0 +mallcd,2261,0 +purecord,2261,0 +pudisk,2261,0 +pudisc,2261,0 +pucd,2261,0 +record6,2261,0 +disk6,2261,0 +disc6,2261,0 +cd6,2261,0 +6record,2261,0 +6disk,2261,0 +6disc,2261,0 +6cd,2261,0 +mellohidisc,2262,0 +pinkmusicrecord,2262,0 +pinkmusicdisk,2262,0 +pinkmusicdisc,2262,0 +pinkmusiccd,2262,0 +mellohimusicrecord,2262,0 +mellohimusicdisk,2262,0 +mellohimusicdisc,2262,0 +mellohimusiccd,2262,0 +pimusicrecord,2262,0 +pimusicdisk,2262,0 +pimusicdisc,2262,0 +pimusiccd,2262,0 +pinkmrecord,2262,0 +pinkmdisk,2262,0 +pinkmdisc,2262,0 +pinkmcd,2262,0 +mellohimrecord,2262,0 +mellohimdisk,2262,0 +mellohimdisc,2262,0 +mellohimcd,2262,0 +pimrecord,2262,0 +pimdisk,2262,0 +pimdisc,2262,0 +pimcd,2262,0 +pinkrecord,2262,0 +pinkdisk,2262,0 +pinkdisc,2262,0 +pinkcd,2262,0 +mellohirecord,2262,0 +mellohidisk,2262,0 +mellohicd,2262,0 +pirecord,2262,0 +pidisk,2262,0 +pidisc,2262,0 +picd,2262,0 +record7,2262,0 +disk7,2262,0 +disc7,2262,0 +cd7,2262,0 +7record,2262,0 +7disk,2262,0 +7disc,2262,0 +7cd,2262,0 +staldisc,2263,0 +blackmusicrecord,2263,0 +blackmusicdisk,2263,0 +blackmusicdisc,2263,0 +blackmusiccd,2263,0 +stalmusicrecord,2263,0 +stalmusicdisk,2263,0 +stalmusicdisc,2263,0 +stalmusiccd,2263,0 +blmusicrecord,2263,0 +blmusicdisk,2263,0 +blmusicdisc,2263,0 +blmusiccd,2263,0 +blackmrecord,2263,0 +blackmdisk,2263,0 +blackmdisc,2263,0 +blackmcd,2263,0 +stalmrecord,2263,0 +stalmdisk,2263,0 +stalmdisc,2263,0 +stalmcd,2263,0 +blmrecord,2263,0 +blmdisk,2263,0 +blmdisc,2263,0 +blmcd,2263,0 +blackrecord,2263,0 +blackdisk,2263,0 +blackdisc,2263,0 +blackcd,2263,0 +stalrecord,2263,0 +staldisk,2263,0 +stalcd,2263,0 +blrecord,2263,0 +bldisk,2263,0 +bldisc,2263,0 +blcd,2263,0 +record8,2263,0 +disk8,2263,0 +disc8,2263,0 +cd8,2263,0 +8record,2263,0 +8disk,2263,0 +8disc,2263,0 +8cd,2263,0 +straddisc,2264,0 +whitemusicrecord,2264,0 +whitemusicdisk,2264,0 +whitemusicdisc,2264,0 +whitemusiccd,2264,0 +stradmusicrecord,2264,0 +stradmusicdisk,2264,0 +stradmusicdisc,2264,0 +stradmusiccd,2264,0 +whmusicrecord,2264,0 +whmusicdisk,2264,0 +whmusicdisc,2264,0 +whmusiccd,2264,0 +whitemrecord,2264,0 +whitemdisk,2264,0 +whitemdisc,2264,0 +whitemcd,2264,0 +stradmrecord,2264,0 +stradmdisk,2264,0 +stradmdisc,2264,0 +stradmcd,2264,0 +whmrecord,2264,0 +whmdisk,2264,0 +whmdisc,2264,0 +whmcd,2264,0 +whiterecord,2264,0 +whitedisk,2264,0 +whitedisc,2264,0 +whitecd,2264,0 +stradrecord,2264,0 +straddisk,2264,0 +stradcd,2264,0 +whrecord,2264,0 +whdisk,2264,0 +whdisc,2264,0 +whcd,2264,0 +record9,2264,0 +disk9,2264,0 +disc9,2264,0 +cd9,2264,0 +9record,2264,0 +9disk,2264,0 +9disc,2264,0 +9cd,2264,0 +warddisc,2265,0 +darkgreenmusicrecord,2265,0 +darkgreenmusicdisk,2265,0 +darkgreenmusicdisc,2265,0 +darkgreenmusiccd,2265,0 +dgreenmusicrecord,2265,0 +dgreenmusicdisk,2265,0 +dgreenmusicdisc,2265,0 +dgreenmusiccd,2265,0 +darkgrmusicrecord,2265,0 +darkgrmusicdisk,2265,0 +darkgrmusicdisc,2265,0 +darkgrmusiccd,2265,0 +wardmusicrecord,2265,0 +wardmusicdisk,2265,0 +wardmusicdisc,2265,0 +wardmusiccd,2265,0 +dgrmusicrecord,2265,0 +dgrmusicdisk,2265,0 +dgrmusicdisc,2265,0 +dgrmusiccd,2265,0 +darkgreenmrecord,2265,0 +darkgreenmdisk,2265,0 +darkgreenmdisc,2265,0 +darkgreenmcd,2265,0 +dgreenmrecord,2265,0 +dgreenmdisk,2265,0 +dgreenmdisc,2265,0 +dgreenmcd,2265,0 +darkgrmrecord,2265,0 +darkgrmdisk,2265,0 +darkgrmdisc,2265,0 +darkgrmcd,2265,0 +wardmrecord,2265,0 +wardmdisk,2265,0 +wardmdisc,2265,0 +wardmcd,2265,0 +dgrmrecord,2265,0 +dgrmdisk,2265,0 +dgrmdisc,2265,0 +dgrmcd,2265,0 +darkgreenrecord,2265,0 +darkgreendisk,2265,0 +darkgreendisc,2265,0 +darkgreencd,2265,0 +dgreenrecord,2265,0 +dgreendisk,2265,0 +dgreendisc,2265,0 +dgreencd,2265,0 +darkgrrecord,2265,0 +darkgrdisk,2265,0 +darkgrdisc,2265,0 +darkgrcd,2265,0 +wardrecord,2265,0 +warddisk,2265,0 +wardcd,2265,0 +dgrrecord,2265,0 +dgrdisk,2265,0 +dgrdisc,2265,0 +dgrcd,2265,0 +record10,2265,0 +disk10,2265,0 +disc10,2265,0 +cd10,2265,0 +10record,2265,0 +10disk,2265,0 +10disc,2265,0 +10cd,2265,0 +11disc,2266,0 +crackedmusicrecord,2266,0 +crackedmusicdisk,2266,0 +crackedmusicdisc,2266,0 +crackedmusiccd,2266,0 +crackmusicrecord,2266,0 +crackmusicdisk,2266,0 +crackmusicdisc,2266,0 +crackmusiccd,2266,0 +11musicrecord,2266,0 +11musicdisk,2266,0 +11musicdisc,2266,0 +11musiccd,2266,0 +cmusicrecord,2266,0 +cmusicdisk,2266,0 +cmusicdisc,2266,0 +cmusiccd,2266,0 +crackedmrecord,2266,0 +crackedmdisk,2266,0 +crackedmdisc,2266,0 +crackedmcd,2266,0 +crackmrecord,2266,0 +crackmdisk,2266,0 +crackmdisc,2266,0 +crackmcd,2266,0 +11mrecord,2266,0 +11mdisk,2266,0 +11mdisc,2266,0 +11mcd,2266,0 +cmrecord,2266,0 +cmdisk,2266,0 +cmdisc,2266,0 +cmcd,2266,0 +crackedrecord,2266,0 +crackeddisk,2266,0 +crackeddisc,2266,0 +crackedcd,2266,0 +crackrecord,2266,0 +crackdisk,2266,0 +crackdisc,2266,0 +crackcd,2266,0 +crecord,2266,0 +cdisk,2266,0 +cdisc,2266,0 +ccd,2266,0 +record11,2266,0 +disk11,2266,0 +disc11,2266,0 +cd11,2266,0 +11record,2266,0 +11disk,2266,0 +11cd,2266,0 +waitdisc,2267,0 +waitmusicrecord,2267,0 +waitmusicdisk,2267,0 +waitmusicdisc,2267,0 +waitmusiccd,2267,0 +bluemusicrecord,2267,0 +bluemusicdisk,2267,0 +bluemusicdisc,2267,0 +bluemusiccd,2267,0 +12musicrecord,2267,0 +12musicdisk,2267,0 +12musicdisc,2267,0 +12musiccd,2267,0 +cyanmusicrecord,2267,0 +cyanmusicdisk,2267,0 +cyanmusicdisc,2267,0 +cyanmusiccd,2267,0 +waitmrecord,2267,0 +waitmdisk,2267,0 +waitmdisc,2267,0 +waitmcd,2267,0 +bluemrecord,2267,0 +bluemdisk,2267,0 +bluemdisc,2267,0 +bluemcd,2267,0 +12mrecord,2267,0 +12mdisk,2267,0 +12mdisc,2267,0 +12mcd,2267,0 +cyanmrecord,2267,0 +cyanmdisk,2267,0 +cyanmdisc,2267,0 +cyanmcd,2267,0 +waitrecord,2267,0 +waitdisk,2267,0 +waitcd,2267,0 +bluerecord,2267,0 +bluedisk,2267,0 +bluedisc,2267,0 +bluecd,2267,0 +cyanrecord,2267,0 +cyandisk,2267,0 +cyandisc,2267,0 +cyancd,2267,0 +record12,2267,0 +disk12,2267,0 +disc12,2267,0 +cd12,2267,0 +12record,2267,0 +12disk,2267,0 +12disc,2267,0 +12cd,2267,0 +#4cac18c7e97b9f4cd96d5561a40d7799 \ No newline at end of file diff --git a/src/org/apache/commons/collections4/ArrayStack.java b/src/org/apache/commons/collections4/ArrayStack.java new file mode 100644 index 0000000..2b3b36e --- /dev/null +++ b/src/org/apache/commons/collections4/ArrayStack.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.ArrayList; +import java.util.EmptyStackException; + +/** + * An implementation of the {@link java.util.Stack} API that is based on an + * ArrayList instead of a Vector, so it is not + * synchronized to protect against multi-threaded access. The implementation + * is therefore operates faster in environments where you do not need to + * worry about multiple thread contention. + *

+ * The removal order of an ArrayStack is based on insertion + * order: The most recently added element is removed first. The iteration + * order is not the same as the removal order. The iterator returns + * elements from the bottom up. + *

+ * Unlike Stack, ArrayStack accepts null entries. + *

+ * Note: From version 4.0 onwards, this class does not implement the + * removed {@code Buffer} interface anymore. + * + * @see java.util.Stack + * @since 1.0 + * @version $Id: ArrayStack.java 1477779 2013-04-30 18:55:24Z tn $ + * @deprecated use {@link java.util.ArrayDeque} instead (available from Java 1.6) + */ +@Deprecated +public class ArrayStack extends ArrayList { + + /** Ensure serialization compatibility */ + private static final long serialVersionUID = 2130079159931574599L; + + /** + * Constructs a new empty ArrayStack. The initial size + * is controlled by ArrayList and is currently 10. + */ + public ArrayStack() { + super(); + } + + /** + * Constructs a new empty ArrayStack with an initial size. + * + * @param initialSize the initial size to use + * @throws IllegalArgumentException if the specified initial size + * is negative + */ + public ArrayStack(final int initialSize) { + super(initialSize); + } + + /** + * Return true if this stack is currently empty. + *

+ * This method exists for compatibility with java.util.Stack. + * New users of this class should use isEmpty instead. + * + * @return true if the stack is currently empty + */ + public boolean empty() { + return isEmpty(); + } + + /** + * Returns the top item off of this stack without removing it. + * + * @return the top item on the stack + * @throws EmptyStackException if the stack is empty + */ + public E peek() throws EmptyStackException { + final int n = size(); + if (n <= 0) { + throw new EmptyStackException(); + } else { + return get(n - 1); + } + } + + /** + * Returns the n'th item down (zero-relative) from the top of this + * stack without removing it. + * + * @param n the number of items down to go + * @return the n'th item on the stack, zero relative + * @throws EmptyStackException if there are not enough items on the + * stack to satisfy this request + */ + public E peek(final int n) throws EmptyStackException { + final int m = (size() - n) - 1; + if (m < 0) { + throw new EmptyStackException(); + } else { + return get(m); + } + } + + /** + * Pops the top item off of this stack and return it. + * + * @return the top item on the stack + * @throws EmptyStackException if the stack is empty + */ + public E pop() throws EmptyStackException { + final int n = size(); + if (n <= 0) { + throw new EmptyStackException(); + } else { + return remove(n - 1); + } + } + + /** + * Pushes a new item onto the top of this stack. The pushed item is also + * returned. This is equivalent to calling add. + * + * @param item the item to be added + * @return the item just pushed + */ + public E push(final E item) { + add(item); + return item; + } + + /** + * Returns the one-based position of the distance from the top that the + * specified object exists on this stack, where the top-most element is + * considered to be at distance 1. If the object is not + * present on the stack, return -1 instead. The + * equals() method is used to compare to the items + * in this stack. + * + * @param object the object to be searched for + * @return the 1-based depth into the stack of the object, or -1 if not found + */ + public int search(final Object object) { + int i = size() - 1; // Current index + int n = 1; // Current distance + while (i >= 0) { + final Object current = get(i); + if ((object == null && current == null) || + (object != null && object.equals(current))) { + return n; + } + i--; + n++; + } + return -1; + } + +} diff --git a/src/org/apache/commons/collections4/Bag.java b/src/org/apache/commons/collections4/Bag.java new file mode 100644 index 0000000..dd88ae7 --- /dev/null +++ b/src/org/apache/commons/collections4/Bag.java @@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +/** + * Defines a collection that counts the number of times an object appears in + * the collection. + *

+ * Suppose you have a Bag that contains {a, a, b, c}. + * Calling {@link #getCount(Object)} on a would return 2, while + * calling {@link #uniqueSet()} would return {a, b, c}. + *

+ * NOTE: This interface violates the {@link Collection} contract. + * The behavior specified in many of these methods is not the same + * as the behavior specified by Collection. + * The noncompliant methods are clearly marked with "(Violation)". + * Exercise caution when using a bag as a Collection. + *

+ * This violation resulted from the original specification of this interface. + * In an ideal world, the interface would be changed to fix the problems, however + * it has been decided to maintain backwards compatibility instead. + * + * @param the type held in the bag + * @since 2.0 + * @version $Id: Bag.java 1477779 2013-04-30 18:55:24Z tn $ + */ +public interface Bag extends Collection { + + /** + * Returns the number of occurrences (cardinality) of the given + * object currently in the bag. If the object does not exist in the + * bag, return 0. + * + * @param object the object to search for + * @return the number of occurrences of the object, zero if not found + */ + int getCount(Object object); + + /** + * (Violation) + * Adds one copy of the specified object to the Bag. + *

+ * If the object is already in the {@link #uniqueSet()} then increment its + * count as reported by {@link #getCount(Object)}. Otherwise add it to the + * {@link #uniqueSet()} and report its count as 1. + *

+ * Since this method always increases the size of the bag, + * according to the {@link Collection#add(Object)} contract, it + * should always return true. Since it sometimes returns + * false, this method violates the contract. + * + * @param object the object to add + * @return true if the object was not already in the uniqueSet + */ + boolean add(E object); + + /** + * Adds nCopies copies of the specified object to the Bag. + *

+ * If the object is already in the {@link #uniqueSet()} then increment its + * count as reported by {@link #getCount(Object)}. Otherwise add it to the + * {@link #uniqueSet()} and report its count as nCopies. + * + * @param object the object to add + * @param nCopies the number of copies to add + * @return true if the object was not already in the uniqueSet + */ + boolean add(E object, int nCopies); + + /** + * (Violation) + * Removes all occurrences of the given object from the bag. + *

+ * This will also remove the object from the {@link #uniqueSet()}. + *

+ * According to the {@link Collection#remove(Object)} method, + * this method should only remove the first occurrence of the + * given object, not all occurrences. + * + * @param object the object to remove + * @return true if this call changed the collection + */ + boolean remove(Object object); + + /** + * Removes nCopies copies of the specified object from the Bag. + *

+ * If the number of copies to remove is greater than the actual number of + * copies in the Bag, no error is thrown. + * + * @param object the object to remove + * @param nCopies the number of copies to remove + * @return true if this call changed the collection + */ + boolean remove(Object object, int nCopies); + + /** + * Returns a {@link Set} of unique elements in the Bag. + *

+ * Uniqueness constraints are the same as those in {@link java.util.Set}. + * + * @return the Set of unique Bag elements + */ + Set uniqueSet(); + + /** + * Returns the total number of items in the bag across all types. + * + * @return the total size of the Bag + */ + int size(); + + /** + * (Violation) + * Returns true if the bag contains all elements in + * the given collection, respecting cardinality. That is, if the + * given collection coll contains n copies + * of a given object, calling {@link #getCount(Object)} on that object must + * be >= n for all n in coll. + *

+ * The {@link Collection#containsAll(Collection)} method specifies + * that cardinality should not be respected; this method should + * return true if the bag contains at least one of every object contained + * in the given collection. + * + * @param coll the collection to check against + * @return true if the Bag contains all the collection + */ + boolean containsAll(Collection coll); + + /** + * (Violation) + * Remove all elements represented in the given collection, + * respecting cardinality. That is, if the given collection + * coll contains n copies of a given object, + * the bag will have n fewer copies, assuming the bag + * had at least n copies to begin with. + * + *

The {@link Collection#removeAll(Collection)} method specifies + * that cardinality should not be respected; this method should + * remove all occurrences of every object contained in the + * given collection. + * + * @param coll the collection to remove + * @return true if this call changed the collection + */ + boolean removeAll(Collection coll); + + /** + * (Violation) + * Remove any members of the bag that are not in the given + * collection, respecting cardinality. That is, if the given + * collection coll contains n copies of a + * given object and the bag has m > n copies, then + * delete m - n copies from the bag. In addition, if + * e is an object in the bag but + * !coll.contains(e), then remove e and any + * of its copies. + * + *

The {@link Collection#retainAll(Collection)} method specifies + * that cardinality should not be respected; this method should + * keep all occurrences of every object contained in the + * given collection. + * + * @param coll the collection to retain + * @return true if this call changed the collection + */ + boolean retainAll(Collection coll); + + /** + * Returns an {@link Iterator} over the entire set of members, + * including copies due to cardinality. This iterator is fail-fast + * and will not tolerate concurrent modifications. + * + * @return iterator over all elements in the Bag + */ + Iterator iterator(); + + // The following is not part of the formal Bag interface, however where possible + // Bag implementations should follow these comments. +// /** +// * Compares this Bag to another. +// * This Bag equals another Bag if it contains the same number of occurrences of +// * the same elements. +// * This equals definition is compatible with the Set interface. +// * +// * @param obj the Bag to compare to +// * @return true if equal +// */ +// boolean equals(Object obj); +// +// /** +// * Gets a hash code for the Bag compatible with the definition of equals. +// * The hash code is defined as the sum total of a hash code for each element. +// * The per element hash code is defined as +// * (e==null ? 0 : e.hashCode()) ^ noOccurances). +// * This hash code definition is compatible with the Set interface. +// * +// * @return the hash code of the Bag +// */ +// int hashCode(); + +} diff --git a/src/org/apache/commons/collections4/BagUtils.java b/src/org/apache/commons/collections4/BagUtils.java new file mode 100644 index 0000000..236f808 --- /dev/null +++ b/src/org/apache/commons/collections4/BagUtils.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import org.apache.commons.collections4.bag.CollectionBag; +import org.apache.commons.collections4.bag.HashBag; +import org.apache.commons.collections4.bag.PredicatedBag; +import org.apache.commons.collections4.bag.PredicatedSortedBag; +import org.apache.commons.collections4.bag.SynchronizedBag; +import org.apache.commons.collections4.bag.SynchronizedSortedBag; +import org.apache.commons.collections4.bag.TransformedBag; +import org.apache.commons.collections4.bag.TransformedSortedBag; +import org.apache.commons.collections4.bag.TreeBag; +import org.apache.commons.collections4.bag.UnmodifiableBag; +import org.apache.commons.collections4.bag.UnmodifiableSortedBag; + +/** + * Provides utility methods and decorators for {@link Bag} and {@link SortedBag} instances. + * + * @since 2.1 + * @version $Id: BagUtils.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class BagUtils { + + /** + * An empty unmodifiable bag. + */ + @SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type + public static final Bag EMPTY_BAG = UnmodifiableBag.unmodifiableBag(new HashBag()); + + /** + * An empty unmodifiable sorted bag. + */ + @SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type + public static final Bag EMPTY_SORTED_BAG = + UnmodifiableSortedBag.unmodifiableSortedBag(new TreeBag()); + + /** + * Instantiation of BagUtils is not intended or required. + */ + private BagUtils() {} + + //----------------------------------------------------------------------- + /** + * Returns a synchronized (thread-safe) bag backed by the given bag. In + * order to guarantee serial access, it is critical that all access to the + * backing bag is accomplished through the returned bag. + *

+ * It is imperative that the user manually synchronize on the returned bag + * when iterating over it: + * + *

+     * Bag bag = BagUtils.synchronizedBag(new HashBag());
+     * ...
+     * synchronized(bag) {
+     *     Iterator i = bag.iterator(); // Must be in synchronized block
+     *     while (i.hasNext())
+     *         foo(i.next());
+     *     }
+     * }
+     * 
+ * + * Failure to follow this advice may result in non-deterministic behavior. + * + * @param the element type + * @param bag the bag to synchronize, must not be null + * @return a synchronized bag backed by that bag + * @throws NullPointerException if the Bag is null + */ + public static Bag synchronizedBag(final Bag bag) { + return SynchronizedBag.synchronizedBag(bag); + } + + /** + * Returns an unmodifiable view of the given bag. Any modification attempts + * to the returned bag will raise an {@link UnsupportedOperationException}. + * + * @param the element type + * @param bag the bag whose unmodifiable view is to be returned, must not be null + * @return an unmodifiable view of that bag + * @throws NullPointerException if the Bag is null + */ + public static Bag unmodifiableBag(final Bag bag) { + return UnmodifiableBag.unmodifiableBag(bag); + } + + /** + * Returns a predicated (validating) bag backed by the given bag. + *

+ * Only objects that pass the test in the given predicate can be added to + * the bag. Trying to add an invalid object results in an + * IllegalArgumentException. It is important not to use the original bag + * after invoking this method, as it is a backdoor for adding invalid + * objects. + * + * @param the element type + * @param bag the bag to predicate, must not be null + * @param predicate the predicate for the bag, must not be null + * @return a predicated bag backed by the given bag + * @throws NullPointerException if the Bag or Predicate is null + */ + public static Bag predicatedBag(final Bag bag, final Predicate predicate) { + return PredicatedBag.predicatedBag(bag, predicate); + } + + /** + * Returns a transformed bag backed by the given bag. + *

+ * Each object is passed through the transformer as it is added to the Bag. + * It is important not to use the original bag after invoking this method, + * as it is a backdoor for adding untransformed objects. + *

+ * Existing entries in the specified bag will not be transformed. + * If you want that behaviour, see {@link TransformedBag#transformedBag(Bag, Transformer)}. + * + * @param the element type + * @param bag the bag to predicate, must not be null + * @param transformer the transformer for the bag, must not be null + * @return a transformed bag backed by the given bag + * @throws NullPointerException if the Bag or Transformer is null + */ + public static Bag transformingBag(final Bag bag, final Transformer transformer) { + return TransformedBag.transformingBag(bag, transformer); + } + + /** + * Returns a bag that complies to the Collection contract, backed by the given bag. + * + * @param the element type + * @param bag the bag to decorate, must not be null + * @return a Bag that complies to the Collection contract + * @throws NullPointerException if bag is null + * @since 4.0 + */ + public static Bag collectionBag(final Bag bag) { + return CollectionBag.collectionBag(bag); + } + + //----------------------------------------------------------------------- + /** + * Returns a synchronized (thread-safe) sorted bag backed by the given + * sorted bag. In order to guarantee serial access, it is critical that all + * access to the backing bag is accomplished through the returned bag. + *

+ * It is imperative that the user manually synchronize on the returned bag + * when iterating over it: + * + *

+     * SortedBag bag = BagUtils.synchronizedSortedBag(new TreeBag());
+     * ...
+     * synchronized(bag) {
+     *     Iterator i = bag.iterator(); // Must be in synchronized block
+     *     while (i.hasNext())
+     *         foo(i.next());
+     *     }
+     * }
+     * 
+ * + * Failure to follow this advice may result in non-deterministic behavior. + * + * @param the element type + * @param bag the bag to synchronize, must not be null + * @return a synchronized bag backed by that bag + * @throws NullPointerException if the SortedBag is null + */ + public static SortedBag synchronizedSortedBag(final SortedBag bag) { + return SynchronizedSortedBag.synchronizedSortedBag(bag); + } + + /** + * Returns an unmodifiable view of the given sorted bag. Any modification + * attempts to the returned bag will raise an + * {@link UnsupportedOperationException}. + * + * @param the element type + * @param bag the bag whose unmodifiable view is to be returned, must not be null + * @return an unmodifiable view of that bag + * @throws NullPointerException if the SortedBag is null + */ + public static SortedBag unmodifiableSortedBag(final SortedBag bag) { + return UnmodifiableSortedBag.unmodifiableSortedBag(bag); + } + + /** + * Returns a predicated (validating) sorted bag backed by the given sorted + * bag. + *

+ * Only objects that pass the test in the given predicate can be added to + * the bag. Trying to add an invalid object results in an + * IllegalArgumentException. It is important not to use the original bag + * after invoking this method, as it is a backdoor for adding invalid + * objects. + * + * @param the element type + * @param bag the sorted bag to predicate, must not be null + * @param predicate the predicate for the bag, must not be null + * @return a predicated bag backed by the given bag + * @throws NullPointerException if the SortedBag or Predicate is null + */ + public static SortedBag predicatedSortedBag(final SortedBag bag, + final Predicate predicate) { + return PredicatedSortedBag.predicatedSortedBag(bag, predicate); + } + + /** + * Returns a transformed sorted bag backed by the given bag. + *

+ * Each object is passed through the transformer as it is added to the Bag. + * It is important not to use the original bag after invoking this method, + * as it is a backdoor for adding untransformed objects. + *

+ * Existing entries in the specified bag will not be transformed. + * If you want that behaviour, see + * {@link TransformedSortedBag#transformedSortedBag(SortedBag, Transformer)}. + * + * @param the element type + * @param bag the bag to predicate, must not be null + * @param transformer the transformer for the bag, must not be null + * @return a transformed bag backed by the given bag + * @throws NullPointerException if the Bag or Transformer is null + */ + public static SortedBag transformingSortedBag(final SortedBag bag, + final Transformer transformer) { + return TransformedSortedBag.transformingSortedBag(bag, transformer); + } + + /** + * Get an empty Bag. + * + * @param the element type + * @return an empty Bag + */ + @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type + public static Bag emptyBag() { + return (Bag) EMPTY_BAG; + } + + /** + * Get an empty SortedBag. + * + * @param the element type + * @return an empty sorted Bag + */ + @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type + public static SortedBag emptySortedBag() { + return (SortedBag) EMPTY_SORTED_BAG; + } +} diff --git a/src/org/apache/commons/collections4/BidiMap.java b/src/org/apache/commons/collections4/BidiMap.java new file mode 100644 index 0000000..1bb252a --- /dev/null +++ b/src/org/apache/commons/collections4/BidiMap.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Set; + +/** + * Defines a map that allows bidirectional lookup between key and values. + *

+ * This extended Map represents a mapping where a key may + * lookup a value and a value may lookup a key with equal ease. + * This interface extends Map and so may be used anywhere a map + * is required. The interface provides an inverse map view, enabling + * full access to both directions of the BidiMap. + *

+ * Implementations should allow a value to be looked up from a key and + * a key to be looked up from a value with equal performance. + *

+ * This map enforces the restriction that there is a 1:1 relation between + * keys and values, meaning that multiple keys cannot map to the same value. + * This is required so that "inverting" the map results in a map without + * duplicate keys. See the {@link #put} method description for more information. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * + * @since 3.0 + * @version $Id: BidiMap.java 1612021 2014-07-20 04:51:05Z ggregory $ + */ +public interface BidiMap extends IterableMap { + + /** + * Puts the key-value pair into the map, replacing any previous pair. + *

+ * When adding a key-value pair, the value may already exist in the map + * against a different key. That mapping is removed, to ensure that the + * value only occurs once in the inverse map. + *

+     *  BidiMap map1 = new DualHashBidiMap();
+     *  map.put("A","B");  // contains A mapped to B, as per Map
+     *  map.put("A","C");  // contains A mapped to C, as per Map
+     *
+     *  BidiMap map2 = new DualHashBidiMap();
+     *  map.put("A","B");  // contains A mapped to B, as per Map
+     *  map.put("C","B");  // contains C mapped to B, key A is removed
+     * 
+ * + * @param key the key to store + * @param value the value to store + * @return the previous value mapped to this key + * + * @throws UnsupportedOperationException if the put method is not supported + * @throws ClassCastException (optional) if the map limits the type of the + * value and the specified value is inappropriate + * @throws IllegalArgumentException (optional) if the map limits the values + * in some way and the value was invalid + * @throws NullPointerException (optional) if the map limits the values to + * non-null and null was specified + */ + V put(K key, V value); + + /** + * Gets the key that is currently mapped to the specified value. + *

+ * If the value is not contained in the map, null is returned. + *

+ * Implementations should seek to make this method perform equally as well + * as get(Object). + * + * @param value the value to find the key for + * @return the mapped key, or null if not found + * + * @throws ClassCastException (optional) if the map limits the type of the + * value and the specified value is inappropriate + * @throws NullPointerException (optional) if the map limits the values to + * non-null and null was specified + */ + K getKey(Object value); + + /** + * Removes the key-value pair that is currently mapped to the specified + * value (optional operation). + *

+ * If the value is not contained in the map, null is returned. + *

+ * Implementations should seek to make this method perform equally as well + * as remove(Object). + * + * @param value the value to find the key-value pair for + * @return the key that was removed, null if nothing removed + * + * @throws ClassCastException (optional) if the map limits the type of the + * value and the specified value is inappropriate + * @throws NullPointerException (optional) if the map limits the values to + * non-null and null was specified + * @throws UnsupportedOperationException if this method is not supported + * by the implementation + */ + K removeValue(Object value); + + /** + * Gets a view of this map where the keys and values are reversed. + *

+ * Changes to one map will be visible in the other and vice versa. + * This enables both directions of the map to be accessed as a Map. + *

+ * Implementations should seek to avoid creating a new object every time this + * method is called. See AbstractMap.values() etc. Calling this + * method on the inverse map should return the original. + * + * @return an inverted bidirectional map + */ + BidiMap inverseBidiMap(); + + /** + * Returns a {@link Set} view of the values contained in this map. + * 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 Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. + * + * @return a set view of the values contained in this map + */ + Set values(); +} diff --git a/src/org/apache/commons/collections4/BoundedCollection.java b/src/org/apache/commons/collections4/BoundedCollection.java new file mode 100644 index 0000000..6e668ea --- /dev/null +++ b/src/org/apache/commons/collections4/BoundedCollection.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; + +/** + * Defines a collection that is bounded in size. + *

+ * The size of the collection can vary, but it can never exceed a preset + * maximum number of elements. This interface allows the querying of details + * associated with the maximum number of elements. + * + * @see CollectionUtils#isFull + * @see CollectionUtils#maxSize + * + * @since 3.0 + * @version $Id: BoundedCollection.java 1477779 2013-04-30 18:55:24Z tn $ + */ +public interface BoundedCollection extends Collection { + + /** + * Returns true if this collection is full and no new elements can be added. + * + * @return true if the collection is full + */ + boolean isFull(); + + /** + * Gets the maximum size of the collection (the bound). + * + * @return the maximum number of elements the collection can hold + */ + int maxSize(); + +} diff --git a/src/org/apache/commons/collections4/BoundedMap.java b/src/org/apache/commons/collections4/BoundedMap.java new file mode 100644 index 0000000..ce553ab --- /dev/null +++ b/src/org/apache/commons/collections4/BoundedMap.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a map that is bounded in size. + *

+ * The size of the map can vary, but it can never exceed a preset + * maximum number of elements. This interface allows the querying of details + * associated with the maximum number of elements. + * + * @since 3.0 + * @version $Id: BoundedMap.java 1477779 2013-04-30 18:55:24Z tn $ + */ +public interface BoundedMap extends IterableMap { + + /** + * Returns true if this map is full and no new elements can be added. + * + * @return true if the map is full + */ + boolean isFull(); + + /** + * Gets the maximum size of the map (the bound). + * + * @return the maximum number of elements the map can hold + */ + int maxSize(); + +} diff --git a/src/org/apache/commons/collections4/Closure.java b/src/org/apache/commons/collections4/Closure.java new file mode 100644 index 0000000..b71ae12 --- /dev/null +++ b/src/org/apache/commons/collections4/Closure.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a functor interface implemented by classes that do something. + *

+ * A Closure represents a block of code which is executed from + * inside some block, function or iteration. It operates an input object. + *

+ * Standard implementations of common closures are provided by + * {@link ClosureUtils}. These include method invocation and for/while loops. + * + * @param the type that the closure acts on + * @since 1.0 + * @version $Id: Closure.java 1543261 2013-11-19 00:47:34Z ggregory $ + */ +public interface Closure { + + /** + * Performs an action on the specified input object. + * + * @param input the input to execute on + * @throws ClassCastException (runtime) if the input is the wrong class + * @throws IllegalArgumentException (runtime) if the input is invalid + * @throws FunctorException (runtime) if any other error occurs + */ + void execute(T input); + +} diff --git a/src/org/apache/commons/collections4/ClosureUtils.java b/src/org/apache/commons/collections4/ClosureUtils.java new file mode 100644 index 0000000..3a96e6e --- /dev/null +++ b/src/org/apache/commons/collections4/ClosureUtils.java @@ -0,0 +1,377 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Map; + +import org.apache.commons.collections4.functors.ChainedClosure; +import org.apache.commons.collections4.functors.EqualPredicate; +import org.apache.commons.collections4.functors.ExceptionClosure; +import org.apache.commons.collections4.functors.ForClosure; +import org.apache.commons.collections4.functors.IfClosure; +import org.apache.commons.collections4.functors.InvokerTransformer; +import org.apache.commons.collections4.functors.NOPClosure; +import org.apache.commons.collections4.functors.SwitchClosure; +import org.apache.commons.collections4.functors.TransformerClosure; +import org.apache.commons.collections4.functors.WhileClosure; + +/** + * ClosureUtils provides reference implementations and utilities + * for the Closure functor interface. The supplied closures are: + *

    + *
  • Invoker - invokes a method on the input object + *
  • For - repeatedly calls a closure for a fixed number of times + *
  • While - repeatedly calls a closure while a predicate is true + *
  • Chained - chains two or more closures together + *
  • If - calls one closure or another based on a predicate + *
  • Switch - calls one closure based on one or more predicates + *
  • SwitchMap - calls one closure looked up from a Map + *
  • Transformer - wraps a Transformer as a Closure + *
  • NOP - does nothing + *
  • Exception - always throws an exception + *
+ *

+ * Since v4.1 only closures which are considered to be unsafe are + * Serializable. Closures considered to be unsafe for serialization are: + *

    + *
  • Invoker + *
  • For + *
  • While + *
+ * + * @since 3.0 + * @version $Id: ClosureUtils.java 1714362 2015-11-14 20:38:02Z tn $ + */ +public class ClosureUtils { + + /** + * This class is not normally instantiated. + */ + private ClosureUtils() {} + + /** + * Gets a Closure that always throws an exception. + * This could be useful during testing as a placeholder. + * + * @see org.apache.commons.collections4.functors.ExceptionClosure + * + * @param the type that the closure acts on + * @return the closure + */ + public static Closure exceptionClosure() { + return ExceptionClosure.exceptionClosure(); + } + + /** + * Gets a Closure that will do nothing. + * This could be useful during testing as a placeholder. + * + * @see org.apache.commons.collections4.functors.NOPClosure + * + * @param the type that the closure acts on + * @return the closure + */ + public static Closure nopClosure() { + return NOPClosure.nopClosure(); + } + + /** + * Creates a Closure that calls a Transformer each time it is called. + * The transformer will be called using the closure's input object. + * The transformer's result will be ignored. + * + * @see org.apache.commons.collections4.functors.TransformerClosure + * + * @param the type that the closure acts on + * @param transformer the transformer to run each time in the closure, null means nop + * @return the closure + */ + public static Closure asClosure(final Transformer transformer) { + return TransformerClosure.transformerClosure(transformer); + } + + /** + * Creates a Closure that will call the closure count times. + *

+ * A null closure or zero count returns the NOPClosure. + * + * @see org.apache.commons.collections4.functors.ForClosure + * + * @param the type that the closure acts on + * @param count the number of times to loop + * @param closure the closure to call repeatedly + * @return the for closure + */ + public static Closure forClosure(final int count, final Closure closure) { + return ForClosure.forClosure(count, closure); + } + + /** + * Creates a Closure that will call the closure repeatedly until the + * predicate returns false. + * + * @see org.apache.commons.collections4.functors.WhileClosure + * + * @param the type that the closure acts on + * @param predicate the predicate to use as an end of loop test, not null + * @param closure the closure to call repeatedly, not null + * @return the while closure + * @throws NullPointerException if either argument is null + */ + public static Closure whileClosure(final Predicate predicate, final Closure closure) { + return WhileClosure.whileClosure(predicate, closure, false); + } + + /** + * Creates a Closure that will call the closure once and then repeatedly + * until the predicate returns false. + * + * @see org.apache.commons.collections4.functors.WhileClosure + * + * @param the type that the closure acts on + * @param closure the closure to call repeatedly, not null + * @param predicate the predicate to use as an end of loop test, not null + * @return the do-while closure + * @throws NullPointerException if either argument is null + */ + public static Closure doWhileClosure(final Closure closure, + final Predicate predicate) { + return WhileClosure.whileClosure(predicate, closure, true); + } + + /** + * Creates a Closure that will invoke a specific method on the closure's + * input object by reflection. + * + * @see org.apache.commons.collections4.functors.InvokerTransformer + * @see org.apache.commons.collections4.functors.TransformerClosure + * + * @param the type that the closure acts on + * @param methodName the name of the method + * @return the invoker closure + * @throws NullPointerException if the method name is null + */ + public static Closure invokerClosure(final String methodName) { + // reuse transformer as it has caching - this is lazy really, should have inner class here + return asClosure(InvokerTransformer.invokerTransformer(methodName)); + } + + /** + * Creates a Closure that will invoke a specific method on the closure's + * input object by reflection. + * + * @see org.apache.commons.collections4.functors.InvokerTransformer + * @see org.apache.commons.collections4.functors.TransformerClosure + * + * @param the type that the closure acts on + * @param methodName the name of the method + * @param paramTypes the parameter types + * @param args the arguments + * @return the invoker closure + * @throws NullPointerException if the method name is null + * @throws IllegalArgumentException if the paramTypes and args don't match + */ + public static Closure invokerClosure(final String methodName, final Class[] paramTypes, + final Object[] args) { + // reuse transformer as it has caching - this is lazy really, should have inner class here + return asClosure(InvokerTransformer.invokerTransformer(methodName, paramTypes, args)); + } + + /** + * Create a new Closure that calls each closure in turn, passing the + * result into the next closure. + * + * @see org.apache.commons.collections4.functors.ChainedClosure + * + * @param the type that the closure acts on + * @param closures an array of closures to chain + * @return the chained closure + * @throws NullPointerException if the closures array is null + * @throws NullPointerException if any closure in the array is null + */ + @SafeVarargs + public static Closure chainedClosure(final Closure... closures) { + return ChainedClosure.chainedClosure(closures); + } + + /** + * Create a new Closure that calls each closure in turn, passing the + * result into the next closure. The ordering is that of the iterator() + * method on the collection. + * + * @see org.apache.commons.collections4.functors.ChainedClosure + * + * @param the type that the closure acts on + * @param closures a collection of closures to chain + * @return the chained closure + * @throws NullPointerException if the closures collection is null + * @throws NullPointerException if any closure in the collection is null + * @throws IllegalArgumentException if the closures collection is empty + */ + public static Closure chainedClosure(final Collection> closures) { + return ChainedClosure.chainedClosure(closures); + } + + /** + * Create a new Closure that calls another closure based on the + * result of the specified predicate. + * + * @see org.apache.commons.collections4.functors.IfClosure + * + * @param the type that the closure acts on + * @param predicate the validating predicate + * @param trueClosure the closure called if the predicate is true + * @return the if closure + * @throws NullPointerException if the predicate or closure is null + * @since 3.2 + */ + public static Closure ifClosure(final Predicate predicate, + final Closure trueClosure) { + return IfClosure.ifClosure(predicate, trueClosure); + } + + /** + * Create a new Closure that calls one of two closures depending + * on the specified predicate. + * + * @see org.apache.commons.collections4.functors.IfClosure + * + * @param the type that the closure acts on + * @param predicate the predicate to switch on + * @param trueClosure the closure called if the predicate is true + * @param falseClosure the closure called if the predicate is false + * @return the switch closure + * @throws NullPointerException if the predicate or either closure is null + */ + public static Closure ifClosure(final Predicate predicate, + final Closure trueClosure, + final Closure falseClosure) { + return IfClosure.ifClosure(predicate, trueClosure, falseClosure); + } + + /** + * Create a new Closure that calls one of the closures depending + * on the predicates. + *

+ * The closure at array location 0 is called if the predicate at array + * location 0 returned true. Each predicate is evaluated + * until one returns true. + * + * @see org.apache.commons.collections4.functors.SwitchClosure + * + * @param the type that the closure acts on + * @param predicates an array of predicates to check, not null + * @param closures an array of closures to call, not null + * @return the switch closure + * @throws NullPointerException if the either array is null + * @throws NullPointerException if any element in the arrays is null + * @throws IllegalArgumentException if the arrays have different sizes + */ + public static Closure switchClosure(final Predicate[] predicates, + final Closure[] closures) { + return SwitchClosure.switchClosure(predicates, closures, null); + } + + /** + * Create a new Closure that calls one of the closures depending + * on the predicates. + *

+ * The closure at array location 0 is called if the predicate at array + * location 0 returned true. Each predicate is evaluated + * until one returns true. If no predicates evaluate to true, the default + * closure is called. + * + * @see org.apache.commons.collections4.functors.SwitchClosure + * + * @param the type that the closure acts on + * @param predicates an array of predicates to check, not null + * @param closures an array of closures to call, not null + * @param defaultClosure the default to call if no predicate matches + * @return the switch closure + * @throws NullPointerException if the either array is null + * @throws NullPointerException if any element in the arrays is null + * @throws IllegalArgumentException if the arrays are different sizes + */ + public static Closure switchClosure(final Predicate[] predicates, + final Closure[] closures, + final Closure defaultClosure) { + return SwitchClosure.switchClosure(predicates, closures, defaultClosure); + } + + /** + * Create a new Closure that calls one of the closures depending + * on the predicates. + *

+ * The Map consists of Predicate keys and Closure values. A closure + * is called if its matching predicate returns true. Each predicate is evaluated + * until one returns true. If no predicates evaluate to true, the default + * closure is called. The default closure is set in the map with a + * null key. The ordering is that of the iterator() method on the entryset + * collection of the map. + * + * @see org.apache.commons.collections4.functors.SwitchClosure + * + * @param the type that the closure acts on + * @param predicatesAndClosures a map of predicates to closures + * @return the switch closure + * @throws NullPointerException if the map is null + * @throws NullPointerException if any closure in the map is null + * @throws IllegalArgumentException if the map is empty + * @throws ClassCastException if the map elements are of the wrong type + */ + public static Closure switchClosure(final Map, Closure> predicatesAndClosures) { + return SwitchClosure.switchClosure(predicatesAndClosures); + } + + /** + * Create a new Closure that uses the input object as a key to find the + * closure to call. + *

+ * The Map consists of object keys and Closure values. A closure + * is called if the input object equals the key. If there is no match, the + * default closure is called. The default closure is set in the map + * using a null key. + * + * @see org.apache.commons.collections4.functors.SwitchClosure + * + * @param the type that the closure acts on + * @param objectsAndClosures a map of objects to closures + * @return the closure + * @throws NullPointerException if the map is null + * @throws NullPointerException if any closure in the map is null + * @throws IllegalArgumentException if the map is empty + */ + @SuppressWarnings("unchecked") + public static Closure switchMapClosure(final Map> objectsAndClosures) { + if (objectsAndClosures == null) { + throw new NullPointerException("The object and closure map must not be null"); + } + final Closure def = objectsAndClosures.remove(null); + final int size = objectsAndClosures.size(); + final Closure[] trs = new Closure[size]; + final Predicate[] preds = new Predicate[size]; + int i = 0; + for (final Map.Entry> entry : objectsAndClosures.entrySet()) { + preds[i] = EqualPredicate.equalPredicate(entry.getKey()); + trs[i] = entry.getValue(); + i++; + } + return ClosureUtils.switchClosure(preds, trs, def); + } + +} diff --git a/src/org/apache/commons/collections4/CollectionUtils.java b/src/org/apache/commons/collections4/CollectionUtils.java new file mode 100644 index 0000000..7575ea7 --- /dev/null +++ b/src/org/apache/commons/collections4/CollectionUtils.java @@ -0,0 +1,1892 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.bag.HashBag; +import org.apache.commons.collections4.collection.PredicatedCollection; +import org.apache.commons.collections4.collection.SynchronizedCollection; +import org.apache.commons.collections4.collection.TransformedCollection; +import org.apache.commons.collections4.collection.UnmodifiableBoundedCollection; +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.functors.TruePredicate; +import org.apache.commons.collections4.iterators.CollatingIterator; +import org.apache.commons.collections4.iterators.PermutationIterator; + +/** + * Provides utility methods and decorators for {@link Collection} instances. + *

+ * Various utility methods might put the input objects into a Set/Map/Bag. In case + * the input objects override {@link Object#equals(Object)}, it is mandatory that + * the general contract of the {@link Object#hashCode()} method is maintained. + *

+ * NOTE: From 4.0, method parameters will take {@link Iterable} objects when possible. + * + * @since 1.0 + * @version $Id: CollectionUtils.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class CollectionUtils { + + /** + * Helper class to easily access cardinality properties of two collections. + * @param the element type + */ + private static class CardinalityHelper { + + /** Contains the cardinality for each object in collection A. */ + final Map cardinalityA; + + /** Contains the cardinality for each object in collection B. */ + final Map cardinalityB; + + /** + * Create a new CardinalityHelper for two collections. + * @param a the first collection + * @param b the second collection + */ + public CardinalityHelper(final Iterable a, final Iterable b) { + cardinalityA = CollectionUtils.getCardinalityMap(a); + cardinalityB = CollectionUtils.getCardinalityMap(b); + } + + /** + * Returns the maximum frequency of an object. + * @param obj the object + * @return the maximum frequency of the object + */ + public final int max(final Object obj) { + return Math.max(freqA(obj), freqB(obj)); + } + + /** + * Returns the minimum frequency of an object. + * @param obj the object + * @return the minimum frequency of the object + */ + public final int min(final Object obj) { + return Math.min(freqA(obj), freqB(obj)); + } + + /** + * Returns the frequency of this object in collection A. + * @param obj the object + * @return the frequency of the object in collection A + */ + public int freqA(final Object obj) { + return getFreq(obj, cardinalityA); + } + + /** + * Returns the frequency of this object in collection B. + * @param obj the object + * @return the frequency of the object in collection B + */ + public int freqB(final Object obj) { + return getFreq(obj, cardinalityB); + } + + private final int getFreq(final Object obj, final Map freqMap) { + final Integer count = freqMap.get(obj); + if (count != null) { + return count.intValue(); + } + return 0; + } + } + + /** + * Helper class for set-related operations, e.g. union, subtract, intersection. + * @param the element type + */ + private static class SetOperationCardinalityHelper extends CardinalityHelper implements Iterable { + + /** Contains the unique elements of the two collections. */ + private final Set elements; + + /** Output collection. */ + private final List newList; + + /** + * Create a new set operation helper from the two collections. + * @param a the first collection + * @param b the second collection + */ + public SetOperationCardinalityHelper(final Iterable a, final Iterable b) { + super(a, b); + elements = new HashSet(); + addAll(elements, a); + addAll(elements, b); + // the resulting list must contain at least each unique element, but may grow + newList = new ArrayList(elements.size()); + } + + public Iterator iterator() { + return elements.iterator(); + } + + /** + * Add the object {@code count} times to the result collection. + * @param obj the object to add + * @param count the count + */ + public void setCardinality(final O obj, final int count) { + for (int i = 0; i < count; i++) { + newList.add(obj); + } + } + + /** + * Returns the resulting collection. + * @return the result + */ + public Collection list() { + return newList; + } + + } + + /** + * An empty unmodifiable collection. + * The JDK provides empty Set and List implementations which could be used for + * this purpose. However they could be cast to Set or List which might be + * undesirable. This implementation only implements Collection. + */ + @SuppressWarnings("rawtypes") // we deliberately use the raw type here + public static final Collection EMPTY_COLLECTION = + UnmodifiableCollection.unmodifiableCollection(new ArrayList()); + + /** + * CollectionUtils should not normally be instantiated. + */ + private CollectionUtils() {} + + /** + * Returns the immutable EMPTY_COLLECTION with generic type safety. + * + * @see #EMPTY_COLLECTION + * @since 4.0 + * @param the element type + * @return immutable empty collection + */ + @SuppressWarnings("unchecked") // OK, empty collection is compatible with any type + public static Collection emptyCollection() { + return EMPTY_COLLECTION; + } + + /** + * Returns an immutable empty collection if the argument is null, + * or the argument itself otherwise. + * + * @param the element type + * @param collection the collection, possibly null + * @return an empty collection if the argument is null + */ + @SuppressWarnings("unchecked") // OK, empty collection is compatible with any type + public static Collection emptyIfNull(final Collection collection) { + return collection == null ? EMPTY_COLLECTION : collection; + } + + /** + * Returns a {@link Collection} containing the union of the given + * {@link Iterable}s. + *

+ * The cardinality of each element in the returned {@link Collection} will + * be equal to the maximum of the cardinality of that element in the two + * given {@link Iterable}s. + * + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @param the generic type that is able to represent the types contained + * in both input collections. + * @return the union of the two collections + * @see Collection#addAll + */ + public static Collection union(final Iterable a, final Iterable b) { + final SetOperationCardinalityHelper helper = new SetOperationCardinalityHelper(a, b); + for (final O obj : helper) { + helper.setCardinality(obj, helper.max(obj)); + } + return helper.list(); + } + + /** + * Returns a {@link Collection} containing the intersection of the given + * {@link Iterable}s. + *

+ * The cardinality of each element in the returned {@link Collection} will + * be equal to the minimum of the cardinality of that element in the two + * given {@link Iterable}s. + * + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @param the generic type that is able to represent the types contained + * in both input collections. + * @return the intersection of the two collections + * @see Collection#retainAll + * @see #containsAny + */ + public static Collection intersection(final Iterable a, final Iterable b) { + final SetOperationCardinalityHelper helper = new SetOperationCardinalityHelper(a, b); + for (final O obj : helper) { + helper.setCardinality(obj, helper.min(obj)); + } + return helper.list(); + } + + /** + * Returns a {@link Collection} containing the exclusive disjunction + * (symmetric difference) of the given {@link Iterable}s. + *

+ * The cardinality of each element e in the returned + * {@link Collection} will be equal to + * max(cardinality(e,a),cardinality(e,b)) - min(cardinality(e,a), + * cardinality(e,b)). + *

+ * This is equivalent to + * {@code {@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})} + * or + * {@code {@link #union union}({@link #subtract subtract(a,b)},{@link #subtract subtract(b,a)})}. + + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @param the generic type that is able to represent the types contained + * in both input collections. + * @return the symmetric difference of the two collections + */ + public static Collection disjunction(final Iterable a, final Iterable b) { + final SetOperationCardinalityHelper helper = new SetOperationCardinalityHelper(a, b); + for (final O obj : helper) { + helper.setCardinality(obj, helper.max(obj) - helper.min(obj)); + } + return helper.list(); + } + + /** + * Returns a new {@link Collection} containing {@code a - b}. + * The cardinality of each element e in the returned {@link Collection} + * will be the cardinality of e in a minus the cardinality + * of e in b, or zero, whichever is greater. + * + * @param a the collection to subtract from, must not be null + * @param b the collection to subtract, must not be null + * @param the generic type that is able to represent the types contained + * in both input collections. + * @return a new collection with the results + * @see Collection#removeAll + */ + public static Collection subtract(final Iterable a, final Iterable b) { + final Predicate p = TruePredicate.truePredicate(); + return subtract(a, b, p); + } + + /** + * Returns a new {@link Collection} containing a minus a subset of + * b. Only the elements of b that satisfy the predicate + * condition, p are subtracted from a. + * + *

The cardinality of each element e in the returned {@link Collection} + * that satisfies the predicate condition will be the cardinality of e in a + * minus the cardinality of e in b, or zero, whichever is greater.

+ *

The cardinality of each element e in the returned {@link Collection} that does not + * satisfy the predicate condition will be equal to the cardinality of e in a.

+ * + * @param a the collection to subtract from, must not be null + * @param b the collection to subtract, must not be null + * @param p the condition used to determine which elements of b are + * subtracted. + * @param the generic type that is able to represent the types contained + * in both input collections. + * @return a new collection with the results + * @since 4.0 + * @see Collection#removeAll + */ + public static Collection subtract(final Iterable a, + final Iterable b, + final Predicate p) { + final ArrayList list = new ArrayList(); + final HashBag bag = new HashBag(); + for (final O element : b) { + if (p.evaluate(element)) { + bag.add(element); + } + } + for (final O element : a) { + if (!bag.remove(element, 1)) { + list.add(element); + } + } + return list; + } + + /** + * Returns true iff all elements of {@code coll2} are also contained + * in {@code coll1}. The cardinality of values in {@code coll2} is not taken into account, + * which is the same behavior as {@link Collection#containsAll(Collection)}. + *

+ * In other words, this method returns true iff the + * {@link #intersection} of coll1 and coll2 has the same cardinality as + * the set of unique values from {@code coll2}. In case {@code coll2} is empty, {@code true} + * will be returned. + *

+ * This method is intended as a replacement for {@link Collection#containsAll(Collection)} + * with a guaranteed runtime complexity of {@code O(n + m)}. Depending on the type of + * {@link Collection} provided, this method will be much faster than calling + * {@link Collection#containsAll(Collection)} instead, though this will come at the + * cost of an additional space complexity O(n). + * + * @param coll1 the first collection, must not be null + * @param coll2 the second collection, must not be null + * @return true iff the intersection of the collections has the same cardinality + * as the set of unique elements from the second collection + * @since 4.0 + */ + public static boolean containsAll(final Collection coll1, final Collection coll2) { + if (coll2.isEmpty()) { + return true; + } else { + final Iterator it = coll1.iterator(); + final Set elementsAlreadySeen = new HashSet(); + for (final Object nextElement : coll2) { + if (elementsAlreadySeen.contains(nextElement)) { + continue; + } + + boolean foundCurrentElement = false; + while (it.hasNext()) { + final Object p = it.next(); + elementsAlreadySeen.add(p); + if (nextElement == null ? p == null : nextElement.equals(p)) { + foundCurrentElement = true; + break; + } + } + + if (foundCurrentElement) { + continue; + } else { + return false; + } + } + return true; + } + } + + /** + * Returns true iff at least one element is in both collections. + *

+ * In other words, this method returns true iff the + * {@link #intersection} of coll1 and coll2 is not empty. + * + * @param coll1 the first collection, must not be null + * @param coll2 the second collection, must not be null + * @return true iff the intersection of the collections is non-empty + * @since 2.1 + * @see #intersection + */ + public static boolean containsAny(final Collection coll1, final Collection coll2) { + if (coll1.size() < coll2.size()) { + for (final Object aColl1 : coll1) { + if (coll2.contains(aColl1)) { + return true; + } + } + } else { + for (final Object aColl2 : coll2) { + if (coll1.contains(aColl2)) { + return true; + } + } + } + return false; + } + + /** + * Returns a {@link Map} mapping each unique element in the given + * {@link Collection} to an {@link Integer} representing the number + * of occurrences of that element in the {@link Collection}. + *

+ * Only those elements present in the collection will appear as + * keys in the map. + * + * @param the type of object in the returned {@link Map}. This is a super type of . + * @param coll the collection to get the cardinality map for, must not be null + * @return the populated cardinality map + */ + public static Map getCardinalityMap(final Iterable coll) { + final Map count = new HashMap(); + for (final O obj : coll) { + final Integer c = count.get(obj); + if (c == null) { + count.put(obj, Integer.valueOf(1)); + } else { + count.put(obj, Integer.valueOf(c.intValue() + 1)); + } + } + return count; + } + + /** + * Returns {@code true} iff a is a sub-collection of b, + * that is, iff the cardinality of e in a is less than or + * equal to the cardinality of e in b, for each element e + * in a. + * + * @param a the first (sub?) collection, must not be null + * @param b the second (super?) collection, must not be null + * @return true iff a is a sub-collection of b + * @see #isProperSubCollection + * @see Collection#containsAll + */ + public static boolean isSubCollection(final Collection a, final Collection b) { + final CardinalityHelper helper = new CardinalityHelper(a, b); + for (final Object obj : a) { + if (helper.freqA(obj) > helper.freqB(obj)) { + return false; + } + } + return true; + } + + /** + * Returns {@code true} iff a is a proper sub-collection of b, + * that is, iff the cardinality of e in a is less + * than or equal to the cardinality of e in b, + * for each element e in a, and there is at least one + * element f such that the cardinality of f in b + * is strictly greater than the cardinality of f in a. + *

+ * The implementation assumes + *

    + *
  • a.size() and b.size() represent the + * total cardinality of a and b, resp.
  • + *
  • a.size() < Integer.MAXVALUE
  • + *
+ * + * @param a the first (sub?) collection, must not be null + * @param b the second (super?) collection, must not be null + * @return true iff a is a proper sub-collection of b + * @see #isSubCollection + * @see Collection#containsAll + */ + public static boolean isProperSubCollection(final Collection a, final Collection b) { + return a.size() < b.size() && CollectionUtils.isSubCollection(a, b); + } + + /** + * Returns {@code true} iff the given {@link Collection}s contain + * exactly the same elements with exactly the same cardinalities. + *

+ * That is, iff the cardinality of e in a is + * equal to the cardinality of e in b, + * for each element e in a or b. + * + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @return true iff the collections contain the same elements with the same cardinalities. + */ + public static boolean isEqualCollection(final Collection a, final Collection b) { + if(a.size() != b.size()) { + return false; + } + final CardinalityHelper helper = new CardinalityHelper(a, b); + if(helper.cardinalityA.size() != helper.cardinalityB.size()) { + return false; + } + for( final Object obj : helper.cardinalityA.keySet()) { + if(helper.freqA(obj) != helper.freqB(obj)) { + return false; + } + } + return true; + } + + /** + * Returns {@code true} iff the given {@link Collection}s contain + * exactly the same elements with exactly the same cardinalities. + *

+ * That is, iff the cardinality of e in a is + * equal to the cardinality of e in b, + * for each element e in a or b. + *

+ * Note: from version 4.1 onwards this method requires the input + * collections and equator to be of compatible type (using bounded wildcards). + * Providing incompatible arguments (e.g. by casting to their rawtypes) + * will result in a {@code ClassCastException} thrown at runtime. + * + * @param the element type + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @param equator the Equator used for testing equality + * @return true iff the collections contain the same elements with the same cardinalities. + * @throws NullPointerException if the equator is null + * @since 4.0 + */ + public static boolean isEqualCollection(final Collection a, + final Collection b, + final Equator equator) { + if (equator == null) { + throw new NullPointerException("Equator must not be null."); + } + + if(a.size() != b.size()) { + return false; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Transformer transformer = new Transformer() { + public EquatorWrapper transform(final Object input) { + return new EquatorWrapper(equator, input); + } + }; + + return isEqualCollection(collect(a, transformer), collect(b, transformer)); + } + + /** + * Wraps another object and uses the provided Equator to implement + * {@link #equals(Object)} and {@link #hashCode()}. + *

+ * This class can be used to store objects into a Map. + * + * @param the element type + * @since 4.0 + */ + private static class EquatorWrapper { + private final Equator equator; + private final O object; + + public EquatorWrapper(final Equator equator, final O object) { + this.equator = equator; + this.object = object; + } + + public O getObject() { + return object; + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof EquatorWrapper)) { + return false; + } + @SuppressWarnings("unchecked") + final EquatorWrapper otherObj = (EquatorWrapper) obj; + return equator.equate(object, otherObj.getObject()); + } + + @Override + public int hashCode() { + return equator.hash(object); + } + } + + /** + * Returns the number of occurrences of obj in coll. + * + * @param obj the object to find the cardinality of + * @param coll the {@link Iterable} to search + * @param the type of object that the {@link Iterable} may contain. + * @return the the number of occurrences of obj in coll + * @throws NullPointerException if coll is null + * @deprecated since 4.1, use {@link IterableUtils#frequency(Iterable, Object)} instead. + * Be aware that the order of parameters has changed. + */ + @Deprecated + public static int cardinality(final O obj, final Iterable coll) { + if (coll == null) { + throw new NullPointerException("coll must not be null."); + } + return IterableUtils.frequency(coll, obj); + } + + /** + * Finds the first element in the given collection which matches the given predicate. + *

+ * If the input collection or predicate is null, or no element of the collection + * matches the predicate, null is returned. + * + * @param the type of object the {@link Iterable} contains + * @param collection the collection to search, may be null + * @param predicate the predicate to use, may be null + * @return the first element of the collection which matches the predicate or null if none could be found + * @deprecated since 4.1, use {@link IterableUtils#find(Iterable, Predicate)} instead + */ + @Deprecated + public static T find(final Iterable collection, final Predicate predicate) { + return predicate != null ? IterableUtils.find(collection, predicate) : null; + } + + /** + * Executes the given closure on each element in the collection. + *

+ * If the input collection or closure is null, there is no change made. + * + * @param the type of object the {@link Iterable} contains + * @param the closure type + * @param collection the collection to get the input from, may be null + * @param closure the closure to perform, may be null + * @return closure + * @deprecated since 4.1, use {@link IterableUtils#forEach(Iterable, Closure)} instead + */ + @Deprecated + public static > C forAllDo(final Iterable collection, final C closure) { + if (closure != null) { + IterableUtils.forEach(collection, closure); + } + return closure; + } + + /** + * Executes the given closure on each element in the collection. + *

+ * If the input collection or closure is null, there is no change made. + * + * @param the type of object the {@link Iterator} contains + * @param the closure type + * @param iterator the iterator to get the input from, may be null + * @param closure the closure to perform, may be null + * @return closure + * @since 4.0 + * @deprecated since 4.1, use {@link IteratorUtils#forEach(Iterator, Closure)} instead + */ + @Deprecated + public static > C forAllDo(final Iterator iterator, final C closure) { + if (closure != null) { + IteratorUtils.forEach(iterator, closure); + } + return closure; + } + + /** + * Executes the given closure on each but the last element in the collection. + *

+ * If the input collection or closure is null, there is no change made. + * + * @param the type of object the {@link Iterable} contains + * @param the closure type + * @param collection the collection to get the input from, may be null + * @param closure the closure to perform, may be null + * @return the last element in the collection, or null if either collection or closure is null + * @since 4.0 + * @deprecated since 4.1, use {@link IterableUtils#forEachButLast(Iterable, Closure)} instead + */ + @Deprecated + public static > T forAllButLastDo(final Iterable collection, + final C closure) { + return closure != null ? IterableUtils.forEachButLast(collection, closure) : null; + } + + /** + * Executes the given closure on each but the last element in the collection. + *

+ * If the input collection or closure is null, there is no change made. + * + * @param the type of object the {@link Collection} contains + * @param the closure type + * @param iterator the iterator to get the input from, may be null + * @param closure the closure to perform, may be null + * @return the last element in the collection, or null if either iterator or closure is null + * @since 4.0 + * @deprecated since 4.1, use {@link IteratorUtils#forEachButLast(Iterator, Closure)} instead + */ + @Deprecated + public static > T forAllButLastDo(final Iterator iterator, final C closure) { + return closure != null ? IteratorUtils.forEachButLast(iterator, closure) : null; + } + + /** + * Filter the collection by applying a Predicate to each element. If the + * predicate returns false, remove the element. + *

+ * If the input collection or predicate is null, there is no change made. + * + * @param the type of object the {@link Iterable} contains + * @param collection the collection to get the input from, may be null + * @param predicate the predicate to use as a filter, may be null + * @return true if the collection is modified by this call, false otherwise. + */ + public static boolean filter(final Iterable collection, final Predicate predicate) { + boolean result = false; + if (collection != null && predicate != null) { + for (final Iterator it = collection.iterator(); it.hasNext();) { + if (!predicate.evaluate(it.next())) { + it.remove(); + result = true; + } + } + } + return result; + } + + /** + * Filter the collection by applying a Predicate to each element. If the + * predicate returns true, remove the element. + *

+ * This is equivalent to

filter(collection, PredicateUtils.notPredicate(predicate))
+ * if predicate is != null. + *

+ * If the input collection or predicate is null, there is no change made. + * + * @param the type of object the {@link Iterable} contains + * @param collection the collection to get the input from, may be null + * @param predicate the predicate to use as a filter, may be null + * @return true if the collection is modified by this call, false otherwise. + */ + public static boolean filterInverse(final Iterable collection, final Predicate predicate) { + return filter(collection, predicate == null ? null : PredicateUtils.notPredicate(predicate)); + } + + /** + * Transform the collection by applying a Transformer to each element. + *

+ * If the input collection or transformer is null, there is no change made. + *

+ * This routine is best for Lists, for which set() is used to do the + * transformations "in place." For other Collections, clear() and addAll() + * are used to replace elements. + *

+ * If the input collection controls its input, such as a Set, and the + * Transformer creates duplicates (or are otherwise invalid), the collection + * may reduce in size due to calling this method. + * + * @param the type of object the {@link Collection} contains + * @param collection the {@link Collection} to get the input from, may be null + * @param transformer the transformer to perform, may be null + */ + public static void transform(final Collection collection, + final Transformer transformer) { + + if (collection != null && transformer != null) { + if (collection instanceof List) { + final List list = (List) collection; + for (final ListIterator it = list.listIterator(); it.hasNext();) { + it.set(transformer.transform(it.next())); + } + } else { + final Collection resultCollection = collect(collection, transformer); + collection.clear(); + collection.addAll(resultCollection); + } + } + } + + /** + * Counts the number of elements in the input collection that match the + * predicate. + *

+ * A null collection or predicate matches no elements. + * + * @param the type of object the {@link Iterable} contains + * @param input the {@link Iterable} to get the input from, may be null + * @param predicate the predicate to use, may be null + * @return the number of matches for the predicate in the collection + * @deprecated since 4.1, use {@link IterableUtils#countMatches(Iterable, Predicate)} instead + */ + @Deprecated + public static int countMatches(final Iterable input, final Predicate predicate) { + return predicate == null ? 0 : (int) IterableUtils.countMatches(input, predicate); + } + + /** + * Answers true if a predicate is true for at least one element of a + * collection. + *

+ * A null collection or predicate returns false. + * + * @param the type of object the {@link Iterable} contains + * @param input the {@link Iterable} to get the input from, may be null + * @param predicate the predicate to use, may be null + * @return true if at least one element of the collection matches the predicate + * @deprecated since 4.1, use {@link IterableUtils#matchesAny(Iterable, Predicate)} instead + */ + @Deprecated + public static boolean exists(final Iterable input, final Predicate predicate) { + return predicate == null ? false : IterableUtils.matchesAny(input, predicate); + } + + /** + * Answers true if a predicate is true for every element of a + * collection. + *

+ * A null predicate returns false.
+ * A null or empty collection returns true. + * + * @param the type of object the {@link Iterable} contains + * @param input the {@link Iterable} to get the input from, may be null + * @param predicate the predicate to use, may be null + * @return true if every element of the collection matches the predicate or if the + * collection is empty, false otherwise + * @since 4.0 + * @deprecated since 4.1, use {@link IterableUtils#matchesAll(Iterable, Predicate)} instead + */ + @Deprecated + public static boolean matchesAll(final Iterable input, final Predicate predicate) { + return predicate == null ? false : IterableUtils.matchesAll(input, predicate); + } + + /** + * Selects all elements from input collection which match the given + * predicate into an output collection. + *

+ * A null predicate matches no elements. + * + * @param the type of object the {@link Iterable} contains + * @param inputCollection the collection to get the input from, may not be null + * @param predicate the predicate to use, may be null + * @return the elements matching the predicate (new list) + * @throws NullPointerException if the input collection is null + */ + public static Collection select(final Iterable inputCollection, + final Predicate predicate) { + final Collection answer = inputCollection instanceof Collection ? + new ArrayList(((Collection) inputCollection).size()) : new ArrayList(); + return select(inputCollection, predicate, answer); + } + + /** + * Selects all elements from input collection which match the given + * predicate and adds them to outputCollection. + *

+ * If the input collection or predicate is null, there is no change to the + * output collection. + * + * @param the type of object the {@link Iterable} contains + * @param the type of the output {@link Collection} + * @param inputCollection the collection to get the input from, may be null + * @param predicate the predicate to use, may be null + * @param outputCollection the collection to output into, may not be null if the inputCollection + * and predicate or not null + * @return the outputCollection + */ + public static > R select(final Iterable inputCollection, + final Predicate predicate, final R outputCollection) { + + if (inputCollection != null && predicate != null) { + for (final O item : inputCollection) { + if (predicate.evaluate(item)) { + outputCollection.add(item); + } + } + } + return outputCollection; + } + + /** + * Selects all elements from inputCollection into an output and rejected collection, + * based on the evaluation of the given predicate. + *

+ * Elements matching the predicate are added to the outputCollection, + * all other elements are added to the rejectedCollection. + *

+ * If the input predicate is null, no elements are added to + * outputCollection or rejectedCollection. + *

+ * Note: calling the method is equivalent to the following code snippet: + *

+     *   select(inputCollection, predicate, outputCollection);
+     *   selectRejected(inputCollection, predicate, rejectedCollection);
+     * 
+ * + * @param the type of object the {@link Iterable} contains + * @param the type of the output {@link Collection} + * @param inputCollection the collection to get the input from, may be null + * @param predicate the predicate to use, may be null + * @param outputCollection the collection to output selected elements into, may not be null if the + * inputCollection and predicate are not null + * @param rejectedCollection the collection to output rejected elements into, may not be null if the + * inputCollection or predicate are not null + * @return the outputCollection + * @since 4.1 + */ + public static > R select(final Iterable inputCollection, + final Predicate predicate, R outputCollection, R rejectedCollection) { + + if (inputCollection != null && predicate != null) { + for (final O element : inputCollection) { + if (predicate.evaluate(element)) { + outputCollection.add(element); + } else { + rejectedCollection.add(element); + } + } + } + return outputCollection; + } + + /** + * Selects all elements from inputCollection which don't match the given + * predicate into an output collection. + *

+ * If the input predicate is null, the result is an empty + * list. + * + * @param the type of object the {@link Iterable} contains + * @param inputCollection the collection to get the input from, may not be null + * @param predicate the predicate to use, may be null + * @return the elements not matching the predicate (new list) + * @throws NullPointerException if the input collection is null + */ + public static Collection selectRejected(final Iterable inputCollection, + final Predicate predicate) { + final Collection answer = inputCollection instanceof Collection ? + new ArrayList(((Collection) inputCollection).size()) : new ArrayList(); + return selectRejected(inputCollection, predicate, answer); + } + + /** + * Selects all elements from inputCollection which don't match the given + * predicate and adds them to outputCollection. + *

+ * If the input predicate is null, no elements are added to + * outputCollection. + * + * @param the type of object the {@link Iterable} contains + * @param the type of the output {@link Collection} + * @param inputCollection the collection to get the input from, may be null + * @param predicate the predicate to use, may be null + * @param outputCollection the collection to output into, may not be null if the inputCollection + * and predicate or not null + * @return outputCollection + */ + public static > R selectRejected(final Iterable inputCollection, + final Predicate predicate, final R outputCollection) { + + if (inputCollection != null && predicate != null) { + for (final O item : inputCollection) { + if (!predicate.evaluate(item)) { + outputCollection.add(item); + } + } + } + return outputCollection; + } + + /** + * Returns a new Collection containing all elements of the input collection + * transformed by the given transformer. + *

+ * If the input collection or transformer is null, the result is an empty list. + * + * @param the type of object in the input collection + * @param the type of object in the output collection + * @param inputCollection the collection to get the input from, may not be null + * @param transformer the transformer to use, may be null + * @return the transformed result (new list) + * @throws NullPointerException if the input collection is null + */ + public static Collection collect(final Iterable inputCollection, + final Transformer transformer) { + final Collection answer = inputCollection instanceof Collection ? + new ArrayList(((Collection) inputCollection).size()) : new ArrayList(); + return collect(inputCollection, transformer, answer); + } + + /** + * Transforms all elements from the input iterator with the given transformer + * and adds them to the output collection. + *

+ * If the input iterator or transformer is null, the result is an empty list. + * + * @param the type of object in the input collection + * @param the type of object in the output collection + * @param inputIterator the iterator to get the input from, may be null + * @param transformer the transformer to use, may be null + * @return the transformed result (new list) + */ + public static Collection collect(final Iterator inputIterator, + final Transformer transformer) { + return collect(inputIterator, transformer, new ArrayList()); + } + + /** + * Transforms all elements from input collection with the given transformer + * and adds them to the output collection. + *

+ * If the input collection or transformer is null, there is no change to the + * output collection. + * + * @param the type of object in the input collection + * @param the type of object in the output collection + * @param the type of the output collection + * @param inputCollection the collection to get the input from, may be null + * @param transformer the transformer to use, may be null + * @param outputCollection the collection to output into, may not be null if inputCollection + * and transformer are not null + * @return the output collection with the transformed input added + * @throws NullPointerException if the outputCollection is null and both, inputCollection and + * transformer are not null + */ + public static > R collect(final Iterable inputCollection, + final Transformer transformer, final R outputCollection) { + if (inputCollection != null) { + return collect(inputCollection.iterator(), transformer, outputCollection); + } + return outputCollection; + } + + /** + * Transforms all elements from the input iterator with the given transformer + * and adds them to the output collection. + *

+ * If the input iterator or transformer is null, there is no change to the + * output collection. + * + * @param the type of object in the input collection + * @param the type of object in the output collection + * @param the type of the output collection + * @param inputIterator the iterator to get the input from, may be null + * @param transformer the transformer to use, may be null + * @param outputCollection the collection to output into, may not be null if inputIterator + * and transformer are not null + * @return the outputCollection with the transformed input added + * @throws NullPointerException if the output collection is null and both, inputIterator and + * transformer are not null + */ + public static > R collect(final Iterator inputIterator, + final Transformer transformer, final R outputCollection) { + if (inputIterator != null && transformer != null) { + while (inputIterator.hasNext()) { + final I item = inputIterator.next(); + final O value = transformer.transform(item); + outputCollection.add(value); + } + } + return outputCollection; + } + + //----------------------------------------------------------------------- + /** + * Adds an element to the collection unless the element is null. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to add to, must not be null + * @param object the object to add, if null it will not be added + * @return true if the collection changed + * @throws NullPointerException if the collection is null + * @since 3.2 + */ + public static boolean addIgnoreNull(final Collection collection, final T object) { + if (collection == null) { + throw new NullPointerException("The collection must not be null"); + } + return object != null && collection.add(object); + } + + /** + * Adds all elements in the {@link Iterable} to the given collection. If the + * {@link Iterable} is a {@link Collection} then it is cast and will be + * added using {@link Collection#addAll(Collection)} instead of iterating. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to add to, must not be null + * @param iterable the iterable of elements to add, must not be null + * @return a boolean indicating whether the collection has changed or not. + * @throws NullPointerException if the collection or iterator is null + */ + public static boolean addAll(final Collection collection, final Iterable iterable) { + if (iterable instanceof Collection) { + return collection.addAll((Collection) iterable); + } + return addAll(collection, iterable.iterator()); + } + + /** + * Adds all elements in the iteration to the given collection. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to add to, must not be null + * @param iterator the iterator of elements to add, must not be null + * @return a boolean indicating whether the collection has changed or not. + * @throws NullPointerException if the collection or iterator is null + */ + public static boolean addAll(final Collection collection, final Iterator iterator) { + boolean changed = false; + while (iterator.hasNext()) { + changed |= collection.add(iterator.next()); + } + return changed; + } + + /** + * Adds all elements in the enumeration to the given collection. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to add to, must not be null + * @param enumeration the enumeration of elements to add, must not be null + * @return {@code true} if the collections was changed, {@code false} otherwise + * @throws NullPointerException if the collection or enumeration is null + */ + public static boolean addAll(final Collection collection, final Enumeration enumeration) { + boolean changed = false; + while (enumeration.hasMoreElements()) { + changed |= collection.add(enumeration.nextElement()); + } + return changed; + } + + /** + * Adds all elements in the array to the given collection. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to add to, must not be null + * @param elements the array of elements to add, must not be null + * @return {@code true} if the collection was changed, {@code false} otherwise + * @throws NullPointerException if the collection or array is null + */ + public static boolean addAll(final Collection collection, final C[] elements) { + boolean changed = false; + for (final C element : elements) { + changed |= collection.add(element); + } + return changed; + } + + /** + * Returns the index-th value in {@link Iterator}, throwing + * IndexOutOfBoundsException if there is no such element. + *

+ * The Iterator is advanced to index (or to the end, if + * index exceeds the number of entries) as a side effect of this method. + * + * @param iterator the iterator to get a value from + * @param index the index to get + * @param the type of object in the {@link Iterator} + * @return the object at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + * @throws IllegalArgumentException if the object type is invalid + * @deprecated since 4.1, use {@code IteratorUtils.get(Iterator, int)} instead + */ + @Deprecated + public static T get(final Iterator iterator, final int index) { + return IteratorUtils.get(iterator, index); + } + + /** + * Ensures an index is not negative. + * @param index the index to check. + * @throws IndexOutOfBoundsException if the index is negative. + */ + static void checkIndexBounds(final int index) { + if (index < 0) { + throw new IndexOutOfBoundsException("Index cannot be negative: " + index); + } + } + + /** + * Returns the index-th value in the iterable's {@link Iterator}, throwing + * IndexOutOfBoundsException if there is no such element. + *

+ * If the {@link Iterable} is a {@link List}, then it will use {@link List#get(int)}. + * + * @param iterable the {@link Iterable} to get a value from + * @param index the index to get + * @param the type of object in the {@link Iterable}. + * @return the object at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + * @deprecated since 4.1, use {@code IterableUtils.get(Iterable, int)} instead + */ + @Deprecated + public static T get(final Iterable iterable, final int index) { + return IterableUtils.get(iterable, index); + } + + /** + * Returns the index-th value in object, throwing + * IndexOutOfBoundsException if there is no such element or + * IllegalArgumentException if object is not an + * instance of one of the supported types. + *

+ * The supported types, and associated semantics are: + *

    + *
  • Map -- the value returned is the Map.Entry in position + * index in the map's entrySet iterator, + * if there is such an entry.
  • + *
  • List -- this method is equivalent to the list's get method.
  • + *
  • Array -- the index-th array entry is returned, + * if there is such an entry; otherwise an IndexOutOfBoundsException + * is thrown.
  • + *
  • Collection -- the value returned is the index-th object + * returned by the collection's default iterator, if there is such an element.
  • + *
  • Iterator or Enumeration -- the value returned is the + * index-th object in the Iterator/Enumeration, if there + * is such an element. The Iterator/Enumeration is advanced to + * index (or to the end, if index exceeds the + * number of entries) as a side effect of this method.
  • + *
+ * + * @param object the object to get a value from + * @param index the index to get + * @return the object at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + * @throws IllegalArgumentException if the object type is invalid + */ + public static Object get(final Object object, final int index) { + int i = index; + if (i < 0) { + throw new IndexOutOfBoundsException("Index cannot be negative: " + i); + } + if (object instanceof Map) { + final Map map = (Map) object; + final Iterator iterator = map.entrySet().iterator(); + return IteratorUtils.get(iterator, i); + } else if (object instanceof Object[]) { + return ((Object[]) object)[i]; + } else if (object instanceof Iterator) { + final Iterator it = (Iterator) object; + return IteratorUtils.get(it, i); + } else if (object instanceof Iterable) { + final Iterable iterable = (Iterable) object; + return IterableUtils.get(iterable, i); + } else if (object instanceof Collection) { + final Iterator iterator = ((Collection) object).iterator(); + return IteratorUtils.get(iterator, i); + } else if (object instanceof Enumeration) { + final Enumeration it = (Enumeration) object; + return EnumerationUtils.get(it, i); + } else if (object == null) { + throw new IllegalArgumentException("Unsupported object type: null"); + } else { + try { + return Array.get(object, i); + } catch (final IllegalArgumentException ex) { + throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); + } + } + } + + /** + * Returns the index-th Map.Entry in the map's entrySet, + * throwing IndexOutOfBoundsException if there is no such element. + * + * @param the key type in the {@link Map} + * @param the key type in the {@link Map} + * @param map the object to get a value from + * @param index the index to get + * @return the object at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public static Map.Entry get(final Map map, final int index) { + checkIndexBounds(index); + return get(map.entrySet(), index); + } + + /** + * Gets the size of the collection/iterator specified. + *

+ * This method can handles objects as follows + *

    + *
  • Collection - the collection size + *
  • Map - the map size + *
  • Array - the array size + *
  • Iterator - the number of elements remaining in the iterator + *
  • Enumeration - the number of elements remaining in the enumeration + *
+ * + * @param object the object to get the size of, may be null + * @return the size of the specified collection or 0 if the object was null + * @throws IllegalArgumentException thrown if object is not recognised + * @since 3.1 + */ + public static int size(final Object object) { + if (object == null) { + return 0; + } + int total = 0; + if (object instanceof Map) { + total = ((Map) object).size(); + } else if (object instanceof Collection) { + total = ((Collection) object).size(); + } else if (object instanceof Iterable) { + total = IterableUtils.size((Iterable) object); + } else if (object instanceof Object[]) { + total = ((Object[]) object).length; + } else if (object instanceof Iterator) { + total = IteratorUtils.size((Iterator) object); + } else if (object instanceof Enumeration) { + final Enumeration it = (Enumeration) object; + while (it.hasMoreElements()) { + total++; + it.nextElement(); + } + } else { + try { + total = Array.getLength(object); + } catch (final IllegalArgumentException ex) { + throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); + } + } + return total; + } + + /** + * Checks if the specified collection/array/iterator is empty. + *

+ * This method can handles objects as follows + *

    + *
  • Collection - via collection isEmpty + *
  • Map - via map isEmpty + *
  • Array - using array size + *
  • Iterator - via hasNext + *
  • Enumeration - via hasMoreElements + *
+ *

+ * Note: This method is named to avoid clashing with + * {@link #isEmpty(Collection)}. + * + * @param object the object to get the size of, may be null + * @return true if empty or null + * @throws IllegalArgumentException thrown if object is not recognised + * @since 3.2 + */ + public static boolean sizeIsEmpty(final Object object) { + if (object == null) { + return true; + } else if (object instanceof Collection) { + return ((Collection) object).isEmpty(); + } else if (object instanceof Iterable) { + return IterableUtils.isEmpty((Iterable) object); + } else if (object instanceof Map) { + return ((Map) object).isEmpty(); + } else if (object instanceof Object[]) { + return ((Object[]) object).length == 0; + } else if (object instanceof Iterator) { + return ((Iterator) object).hasNext() == false; + } else if (object instanceof Enumeration) { + return ((Enumeration) object).hasMoreElements() == false; + } else { + try { + return Array.getLength(object) == 0; + } catch (final IllegalArgumentException ex) { + throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName()); + } + } + } + + //----------------------------------------------------------------------- + /** + * Null-safe check if the specified collection is empty. + *

+ * Null returns true. + * + * @param coll the collection to check, may be null + * @return true if empty or null + * @since 3.2 + */ + public static boolean isEmpty(final Collection coll) { + return coll == null || coll.isEmpty(); + } + + /** + * Null-safe check if the specified collection is not empty. + *

+ * Null returns false. + * + * @param coll the collection to check, may be null + * @return true if non-null and non-empty + * @since 3.2 + */ + public static boolean isNotEmpty(final Collection coll) { + return !isEmpty(coll); + } + + //----------------------------------------------------------------------- + /** + * Reverses the order of the given array. + * + * @param array the array to reverse + */ + public static void reverseArray(final Object[] array) { + int i = 0; + int j = array.length - 1; + Object tmp; + + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + * Returns true if no more elements can be added to the Collection. + *

+ * This method uses the {@link BoundedCollection} interface to determine the + * full status. If the collection does not implement this interface then + * false is returned. + *

+ * The collection does not have to implement this interface directly. + * If the collection has been decorated using the decorators subpackage + * then these will be removed to access the BoundedCollection. + * + * @param coll the collection to check + * @return true if the BoundedCollection is full + * @throws NullPointerException if the collection is null + */ + public static boolean isFull(final Collection coll) { + if (coll == null) { + throw new NullPointerException("The collection must not be null"); + } + if (coll instanceof BoundedCollection) { + return ((BoundedCollection) coll).isFull(); + } + try { + final BoundedCollection bcoll = + UnmodifiableBoundedCollection.unmodifiableBoundedCollection(coll); + return bcoll.isFull(); + } catch (final IllegalArgumentException ex) { + return false; + } + } + + /** + * Get the maximum number of elements that the Collection can contain. + *

+ * This method uses the {@link BoundedCollection} interface to determine the + * maximum size. If the collection does not implement this interface then + * -1 is returned. + *

+ * The collection does not have to implement this interface directly. + * If the collection has been decorated using the decorators subpackage + * then these will be removed to access the BoundedCollection. + * + * @param coll the collection to check + * @return the maximum size of the BoundedCollection, -1 if no maximum size + * @throws NullPointerException if the collection is null + */ + public static int maxSize(final Collection coll) { + if (coll == null) { + throw new NullPointerException("The collection must not be null"); + } + if (coll instanceof BoundedCollection) { + return ((BoundedCollection) coll).maxSize(); + } + try { + final BoundedCollection bcoll = + UnmodifiableBoundedCollection.unmodifiableBoundedCollection(coll); + return bcoll.maxSize(); + } catch (final IllegalArgumentException ex) { + return -1; + } + } + + //----------------------------------------------------------------------- + /** + * Merges two sorted Collections, a and b, into a single, sorted List + * such that the natural ordering of the elements is retained. + *

+ * Uses the standard O(n) merge algorithm for combining two sorted lists. + * + * @param the element type + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @return a new sorted List, containing the elements of Collection a and b + * @throws NullPointerException if either collection is null + * @since 4.0 + */ + public static > List collate(Iterable a, + Iterable b) { + return collate(a, b, ComparatorUtils.naturalComparator(), true); + } + + /** + * Merges two sorted Collections, a and b, into a single, sorted List + * such that the natural ordering of the elements is retained. + *

+ * Uses the standard O(n) merge algorithm for combining two sorted lists. + * + * @param the element type + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @param includeDuplicates if {@code true} duplicate elements will be retained, otherwise + * they will be removed in the output collection + * @return a new sorted List, containing the elements of Collection a and b + * @throws NullPointerException if either collection is null + * @since 4.0 + */ + public static > List collate(final Iterable a, + final Iterable b, + final boolean includeDuplicates) { + return collate(a, b, ComparatorUtils.naturalComparator(), includeDuplicates); + } + + /** + * Merges two sorted Collections, a and b, into a single, sorted List + * such that the ordering of the elements according to Comparator c is retained. + *

+ * Uses the standard O(n) merge algorithm for combining two sorted lists. + * + * @param the element type + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @param c the comparator to use for the merge. + * @return a new sorted List, containing the elements of Collection a and b + * @throws NullPointerException if either collection or the comparator is null + * @since 4.0 + */ + public static List collate(final Iterable a, final Iterable b, + final Comparator c) { + return collate(a, b, c, true); + } + + /** + * Merges two sorted Collections, a and b, into a single, sorted List + * such that the ordering of the elements according to Comparator c is retained. + *

+ * Uses the standard O(n) merge algorithm for combining two sorted lists. + * + * @param the element type + * @param a the first collection, must not be null + * @param b the second collection, must not be null + * @param c the comparator to use for the merge. + * @param includeDuplicates if {@code true} duplicate elements will be retained, otherwise + * they will be removed in the output collection + * @return a new sorted List, containing the elements of Collection a and b + * @throws NullPointerException if either collection or the comparator is null + * @since 4.0 + */ + public static List collate(final Iterable a, final Iterable b, + final Comparator c, final boolean includeDuplicates) { + + if (a == null || b == null) { + throw new NullPointerException("The collections must not be null"); + } + if (c == null) { + throw new NullPointerException("The comparator must not be null"); + } + + // if both Iterables are a Collection, we can estimate the size + final int totalSize = a instanceof Collection && b instanceof Collection ? + Math.max(1, ((Collection) a).size() + ((Collection) b).size()) : 10; + + final Iterator iterator = new CollatingIterator(c, a.iterator(), b.iterator()); + if (includeDuplicates) { + return IteratorUtils.toList(iterator, totalSize); + } else { + final ArrayList mergedList = new ArrayList(totalSize); + + O lastItem = null; + while (iterator.hasNext()) { + final O item = iterator.next(); + if (lastItem == null || !lastItem.equals(item)) { + mergedList.add(item); + } + lastItem = item; + } + + mergedList.trimToSize(); + return mergedList; + } + } + + //----------------------------------------------------------------------- + + /** + * Returns a {@link Collection} of all the permutations of the input collection. + *

+ * NOTE: the number of permutations of a given collection is equal to n!, where + * n is the size of the collection. Thus, the resulting collection will become + * very large for collections > 10 (e.g. 10! = 3628800, 15! = 1307674368000). + *

+ * For larger collections it is advised to use a {@link PermutationIterator} to + * iterate over all permutations. + * + * @see PermutationIterator + * + * @param the element type + * @param collection the collection to create permutations for, may not be null + * @return an unordered collection of all permutations of the input collection + * @throws NullPointerException if collection is null + * @since 4.0 + */ + public static Collection> permutations(final Collection collection) { + final PermutationIterator it = new PermutationIterator(collection); + final Collection> result = new LinkedList>(); + while (it.hasNext()) { + result.add(it.next()); + } + return result; + } + + //----------------------------------------------------------------------- + /** + * Returns a collection containing all the elements in collection + * that are also in retain. The cardinality of an element e + * in the returned collection is the same as the cardinality of e + * in collection unless retain does not contain e, in which + * case the cardinality is zero. This method is useful if you do not wish to modify + * the collection c and thus cannot call c.retainAll(retain);. + *

+ * This implementation iterates over collection, checking each element in + * turn to see if it's contained in retain. If it's contained, it's added + * to the returned list. As a consequence, it is advised to use a collection type for + * retain that provides a fast (e.g. O(1)) implementation of + * {@link Collection#contains(Object)}. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection whose contents are the target of the #retailAll operation + * @param retain the collection containing the elements to be retained in the returned collection + * @return a Collection containing all the elements of collection + * that occur at least once in retain. + * @throws NullPointerException if either parameter is null + * @since 3.2 + */ + public static Collection retainAll(final Collection collection, final Collection retain) { + return ListUtils.retainAll(collection, retain); + } + + /** + * Returns a collection containing all the elements in + * collection that are also in retain. The + * cardinality of an element e in the returned collection is + * the same as the cardinality of e in collection + * unless retain does not contain e, in which case + * the cardinality is zero. This method is useful if you do not wish to + * modify the collection c and thus cannot call + * c.retainAll(retain);. + *

+ * Moreover this method uses an {@link Equator} instead of + * {@link Object#equals(Object)} to determine the equality of the elements + * in collection and retain. Hence this method is + * useful in cases where the equals behavior of an object needs to be + * modified without changing the object itself. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection whose contents are the target of the {@code retainAll} operation + * @param retain the collection containing the elements to be retained in the returned collection + * @param equator the Equator used for testing equality + * @return a Collection containing all the elements of collection + * that occur at least once in retain according to the equator + * @throws NullPointerException if any of the parameters is null + * @since 4.1 + */ + public static Collection retainAll(final Iterable collection, + final Iterable retain, + final Equator equator) { + + final Transformer> transformer = new Transformer>() { + public EquatorWrapper transform(E input) { + return new EquatorWrapper(equator, input); + } + }; + + final Set> retainSet = + collect(retain, transformer, new HashSet>()); + + final List list = new ArrayList(); + for (final E element : collection) { + if (retainSet.contains(new EquatorWrapper(equator, element))) { + list.add(element); + } + } + return list; + } + + /** + * Removes the elements in remove from collection. That is, this + * method returns a collection containing all the elements in c + * that are not in remove. The cardinality of an element e + * in the returned collection is the same as the cardinality of e + * in collection unless remove contains e, in which + * case the cardinality is zero. This method is useful if you do not wish to modify + * the collection c and thus cannot call collection.removeAll(remove);. + *

+ * This implementation iterates over collection, checking each element in + * turn to see if it's contained in remove. If it's not contained, it's added + * to the returned list. As a consequence, it is advised to use a collection type for + * remove that provides a fast (e.g. O(1)) implementation of + * {@link Collection#contains(Object)}. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection from which items are removed (in the returned collection) + * @param remove the items to be removed from the returned collection + * @return a Collection containing all the elements of collection except + * any elements that also occur in remove. + * @throws NullPointerException if either parameter is null + * @since 4.0 (method existed in 3.2 but was completely broken) + */ + public static Collection removeAll(final Collection collection, final Collection remove) { + return ListUtils.removeAll(collection, remove); + } + + /** + * Removes all elements in remove from collection. + * That is, this method returns a collection containing all the elements in + * collection that are not in remove. The + * cardinality of an element e in the returned collection is + * the same as the cardinality of e in collection + * unless remove contains e, in which case the + * cardinality is zero. This method is useful if you do not wish to modify + * the collection c and thus cannot call + * collection.removeAll(remove). + *

+ * Moreover this method uses an {@link Equator} instead of + * {@link Object#equals(Object)} to determine the equality of the elements + * in collection and remove. Hence this method is + * useful in cases where the equals behavior of an object needs to be + * modified without changing the object itself. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection from which items are removed (in the returned collection) + * @param remove the items to be removed from the returned collection + * @param equator the Equator used for testing equality + * @return a Collection containing all the elements of collection + * except any element that if equal according to the equator + * @throws NullPointerException if any of the parameters is null + * @since 4.1 + */ + public static Collection removeAll(final Iterable collection, + final Iterable remove, + final Equator equator) { + + final Transformer> transformer = new Transformer>() { + public EquatorWrapper transform(E input) { + return new EquatorWrapper(equator, input); + } + }; + + final Set> removeSet = + collect(remove, transformer, new HashSet>()); + + final List list = new ArrayList(); + for (final E element : collection) { + if (!removeSet.contains(new EquatorWrapper(equator, element))) { + list.add(element); + } + } + return list; + } + + //----------------------------------------------------------------------- + /** + * Returns a synchronized collection backed by the given collection. + *

+ * You must manually synchronize on the returned buffer's iterator to + * avoid non-deterministic behavior: + * + *

+     * Collection c = CollectionUtils.synchronizedCollection(myCollection);
+     * synchronized (c) {
+     *     Iterator i = c.iterator();
+     *     while (i.hasNext()) {
+     *         process (i.next());
+     *     }
+     * }
+     * 
+ * + * This method uses the implementation in the decorators subpackage. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to synchronize, must not be null + * @return a synchronized collection backed by the given collection + * @throws NullPointerException if the collection is null + * @deprecated since 4.1, use {@link java.util.Collections#synchronizedCollection(Collection)} instead + */ + @Deprecated + public static Collection synchronizedCollection(final Collection collection) { + return SynchronizedCollection.synchronizedCollection(collection); + } + + /** + * Returns an unmodifiable collection backed by the given collection. + *

+ * This method uses the implementation in the decorators subpackage. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to make unmodifiable, must not be null + * @return an unmodifiable collection backed by the given collection + * @throws NullPointerException if the collection is null + * @deprecated since 4.1, use {@link java.util.Collections#unmodifiableCollection(Collection)} instead + */ + @Deprecated + public static Collection unmodifiableCollection(final Collection collection) { + return UnmodifiableCollection.unmodifiableCollection(collection); + } + + /** + * Returns a predicated (validating) collection backed by the given collection. + *

+ * Only objects that pass the test in the given predicate can be added to the collection. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original collection after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the type of objects in the Collection. + * @param collection the collection to predicate, must not be null + * @param predicate the predicate for the collection, must not be null + * @return a predicated collection backed by the given collection + * @throws NullPointerException if the Collection is null + */ + public static Collection predicatedCollection(final Collection collection, + final Predicate predicate) { + return PredicatedCollection.predicatedCollection(collection, predicate); + } + + /** + * Returns a transformed bag backed by the given collection. + *

+ * Each object is passed through the transformer as it is added to the + * Collection. It is important not to use the original collection after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

+ * Existing entries in the specified collection will not be transformed. + * If you want that behaviour, see {@link TransformedCollection#transformedCollection}. + * + * @param the type of object the {@link Collection} contains + * @param collection the collection to predicate, must not be null + * @param transformer the transformer for the collection, must not be null + * @return a transformed collection backed by the given collection + * @throws NullPointerException if the Collection or Transformer is null + */ + public static Collection transformingCollection(final Collection collection, + final Transformer transformer) { + return TransformedCollection.transformingCollection(collection, transformer); + } + + /** + * Extract the lone element of the specified Collection. + * @param collection type + * @param collection to read + * @return sole member of collection + * @throws NullPointerException if collection is null + * @throws IllegalArgumentException if collection is empty or contains more than one element + * @since 4.0 + */ + public static E extractSingleton(final Collection collection) { + if (collection == null) { + throw new NullPointerException("Collection must not be null."); + } + if (collection.size() != 1) { + throw new IllegalArgumentException("Can extract singleton only when collection size == 1"); + } + return collection.iterator().next(); + } +} diff --git a/src/org/apache/commons/collections4/ComparatorUtils.java b/src/org/apache/commons/collections4/ComparatorUtils.java new file mode 100644 index 0000000..8d097ee --- /dev/null +++ b/src/org/apache/commons/collections4/ComparatorUtils.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.collections4.comparators.BooleanComparator; +import org.apache.commons.collections4.comparators.ComparableComparator; +import org.apache.commons.collections4.comparators.ComparatorChain; +import org.apache.commons.collections4.comparators.NullComparator; +import org.apache.commons.collections4.comparators.ReverseComparator; +import org.apache.commons.collections4.comparators.TransformingComparator; + +/** + * Provides convenient static utility methods for Comparator + * objects. + *

+ * Most of the functionality in this class can also be found in the + * comparators package. This class merely provides a + * convenient central place if you have use for more than one class + * in the comparators subpackage. + * + * @since 2.1 + * @version $Id: ComparatorUtils.java 1591832 2014-05-02 08:58:40Z tn $ + */ +public class ComparatorUtils { + + /** + * ComparatorUtils should not normally be instantiated. + */ + private ComparatorUtils() {} + + /** + * Comparator for natural sort order. + * + * @see ComparableComparator#comparableComparator() + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) // explicit type needed for Java 1.5 compilation + public static final Comparator NATURAL_COMPARATOR = ComparableComparator.comparableComparator(); + + /** + * Gets a comparator that uses the natural order of the objects. + * + * @param the object type to compare + * @return a comparator which uses natural order + */ + @SuppressWarnings("unchecked") + public static > Comparator naturalComparator() { + return NATURAL_COMPARATOR; + } + + /** + * Gets a comparator that compares using an array of {@link Comparator}s, applied + * in sequence until one returns not equal or the array is exhausted. + * + * @param the object type to compare + * @param comparators the comparators to use, not null or empty or containing nulls + * @return a {@link ComparatorChain} formed from the input comparators + * @throws NullPointerException if comparators array is null or contains a null + * @see ComparatorChain + */ + @SafeVarargs + public static Comparator chainedComparator(final Comparator... comparators) { + final ComparatorChain chain = new ComparatorChain(); + for (final Comparator comparator : comparators) { + if (comparator == null) { + throw new NullPointerException("Comparator cannot be null"); + } + chain.addComparator(comparator); + } + return chain; + } + + /** + * Gets a comparator that compares using a collection of {@link Comparator}s, + * applied in (default iterator) sequence until one returns not equal or the + * collection is exhausted. + * + * @param the object type to compare + * @param comparators the comparators to use, not null or empty or containing nulls + * @return a {@link ComparatorChain} formed from the input comparators + * @throws NullPointerException if comparators collection is null or contains a null + * @throws ClassCastException if the comparators collection contains the wrong object type + * @see ComparatorChain + */ + @SuppressWarnings("unchecked") + public static Comparator chainedComparator(final Collection> comparators) { + return chainedComparator( + (Comparator[]) comparators.toArray(new Comparator[comparators.size()]) + ); + } + + /** + * Gets a comparator that reverses the order of the given comparator. + * + * @param the object type to compare + * @param comparator the comparator to reverse + * @return a comparator that reverses the order of the input comparator + * @see ReverseComparator + */ + public static Comparator reversedComparator(final Comparator comparator) { + return new ReverseComparator(comparator); + } + + /** + * Gets a Comparator that can sort Boolean objects. + *

+ * The parameter specifies whether true or false is sorted first. + *

+ * The comparator throws NullPointerException if a null value is compared. + * + * @param trueFirst when true, sort + * true {@link Boolean}s before + * false {@link Boolean}s. + * @return a comparator that sorts booleans + */ + public static Comparator booleanComparator(final boolean trueFirst) { + return BooleanComparator.booleanComparator(trueFirst); + } + + /** + * Gets a Comparator that controls the comparison of null values. + *

+ * The returned comparator will consider a null value to be less than + * any nonnull value, and equal to any other null value. Two nonnull + * values will be evaluated with the given comparator. + * + * @param the object type to compare + * @param comparator the comparator that wants to allow nulls + * @return a version of that comparator that allows nulls + * @see NullComparator + */ + @SuppressWarnings("unchecked") + public static Comparator nullLowComparator(Comparator comparator) { + if (comparator == null) { + comparator = NATURAL_COMPARATOR; + } + return new NullComparator(comparator, false); + } + + /** + * Gets a Comparator that controls the comparison of null values. + *

+ * The returned comparator will consider a null value to be greater than + * any nonnull value, and equal to any other null value. Two nonnull + * values will be evaluated with the given comparator. + * + * @param the object type to compare + * @param comparator the comparator that wants to allow nulls + * @return a version of that comparator that allows nulls + * @see NullComparator + */ + @SuppressWarnings("unchecked") + public static Comparator nullHighComparator(Comparator comparator) { + if (comparator == null) { + comparator = NATURAL_COMPARATOR; + } + return new NullComparator(comparator, true); + } + + /** + * Gets a Comparator that passes transformed objects to the given comparator. + *

+ * Objects passed to the returned comparator will first be transformed + * by the given transformer before they are compared by the given + * comparator. + * + * @param the input object type of the transformed comparator + * @param the object type of the decorated comparator + * @param comparator the sort order to use + * @param transformer the transformer to use + * @return a comparator that transforms its input objects before comparing them + * @see TransformingComparator + */ + @SuppressWarnings("unchecked") + public static Comparator transformedComparator(Comparator comparator, + final Transformer transformer) { + + if (comparator == null) { + comparator = NATURAL_COMPARATOR; + } + return new TransformingComparator(transformer, comparator); + } + + /** + * Returns the smaller of the given objects according to the given + * comparator, returning the second object if the comparator + * returns equal. + * + * @param the object type to compare + * @param o1 the first object to compare + * @param o2 the second object to compare + * @param comparator the sort order to use + * @return the smaller of the two objects + */ + @SuppressWarnings("unchecked") + public static E min(final E o1, final E o2, Comparator comparator) { + if (comparator == null) { + comparator = NATURAL_COMPARATOR; + } + final int c = comparator.compare(o1, o2); + return c < 0 ? o1 : o2; + } + + /** + * Returns the larger of the given objects according to the given + * comparator, returning the second object if the comparator + * returns equal. + * + * @param the object type to compare + * @param o1 the first object to compare + * @param o2 the second object to compare + * @param comparator the sort order to use + * @return the larger of the two objects + */ + @SuppressWarnings("unchecked") + public static E max(final E o1, final E o2, Comparator comparator) { + if (comparator == null) { + comparator = NATURAL_COMPARATOR; + } + final int c = comparator.compare(o1, o2); + return c > 0 ? o1 : o2; + } + +} diff --git a/src/org/apache/commons/collections4/EnumerationUtils.java b/src/org/apache/commons/collections4/EnumerationUtils.java new file mode 100644 index 0000000..ad77b76 --- /dev/null +++ b/src/org/apache/commons/collections4/EnumerationUtils.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.commons.collections4.iterators.EnumerationIterator; + +/** + * Provides utility methods for {@link Enumeration} instances. + * + * @since 3.0 + * @version $Id: EnumerationUtils.java 1683009 2015-06-01 21:53:01Z tn $ + */ +public class EnumerationUtils { + + /** + * EnumerationUtils is not normally instantiated. + */ + private EnumerationUtils() {} + + /** + * Returns the index-th value in the {@link Enumeration}, throwing + * IndexOutOfBoundsException if there is no such element. + *

+ * The Enumeration is advanced to index (or to the end, if + * index exceeds the number of entries) as a side effect of this method. + * + * @param e the enumeration to get a value from + * @param index the index to get + * @param the type of object in the {@link Enumeration} + * @return the object at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + * @throws IllegalArgumentException if the object type is invalid + * @since 4.1 + */ + public static T get(final Enumeration e, final int index) { + int i = index; + CollectionUtils.checkIndexBounds(i); + while (e.hasMoreElements()) { + i--; + if (i == -1) { + return e.nextElement(); + } else { + e.nextElement(); + } + } + throw new IndexOutOfBoundsException("Entry does not exist: " + i); + } + + /** + * Creates a list based on an enumeration. + * + *

As the enumeration is traversed, an ArrayList of its values is + * created. The new list is returned.

+ * + * @param the element type + * @param enumeration the enumeration to traverse, which should not be null. + * @return a list containing all elements of the given enumeration + * @throws NullPointerException if the enumeration parameter is null. + */ + public static List toList(final Enumeration enumeration) { + return IteratorUtils.toList(new EnumerationIterator(enumeration)); + } + + /** + * Override toList(Enumeration) for StringTokenizer as it implements Enumeration<Object> + * for the sake of backward compatibility. + * + * @param stringTokenizer the tokenizer to convert to a {@link List}<{@link String}> + * @return a list containing all tokens of the given StringTokenizer + */ + public static List toList(final StringTokenizer stringTokenizer) { + final List result = new ArrayList(stringTokenizer.countTokens()); + while (stringTokenizer.hasMoreTokens()) { + result.add(stringTokenizer.nextToken()); + } + return result; + } +} diff --git a/src/org/apache/commons/collections4/Equator.java b/src/org/apache/commons/collections4/Equator.java new file mode 100644 index 0000000..4ae85fc --- /dev/null +++ b/src/org/apache/commons/collections4/Equator.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License + * for the specific language governing permissions and limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * An equation function, which determines equality between objects of type T. + *

+ * It is the functional sibling of {@link java.util.Comparator}; {@link Equator} is to + * {@link Object} as {@link java.util.Comparator} is to {@link java.lang.Comparable}. + * + * @param the types of object this {@link Equator} can evaluate. + * @since 4.0 + * @version $Id: Equator.java 1540567 2013-11-10 22:19:29Z tn $ + */ +public interface Equator { + /** + * Evaluates the two arguments for their equality. + * + * @param o1 the first object to be equated. + * @param o2 the second object to be equated. + * @return whether the two objects are equal. + */ + boolean equate(T o1, T o2); + + /** + * Calculates the hash for the object, based on the method of equality used in the equate + * method. This is used for classes that delegate their {@link Object#equals(Object) equals(Object)} method to an + * Equator (and so must also delegate their {@link Object#hashCode() hashCode()} method), or for implementations + * of {@link org.apache.commons.collections4.map.HashedMap} that use an Equator for the key objects. + * + * @param o the object to calculate the hash for. + * @return the hash of the object. + */ + int hash(T o); +} diff --git a/src/org/apache/commons/collections4/Factory.java b/src/org/apache/commons/collections4/Factory.java new file mode 100644 index 0000000..159a50b --- /dev/null +++ b/src/org/apache/commons/collections4/Factory.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a functor interface implemented by classes that create objects. + *

+ * A Factory creates an object without using an input parameter. + * If an input parameter is required, then {@link Transformer} is more appropriate. + *

+ * Standard implementations of common factories are provided by + * {@link FactoryUtils}. These include factories that return a constant, + * a copy of a prototype or a new instance. + * + * @param the type that the factory creates + * + * @since 2.1 + * @version $Id: Factory.java 1543256 2013-11-19 00:45:38Z ggregory $ + */ +public interface Factory { + + /** + * Create a new object. + * + * @return a new object + * @throws FunctorException (runtime) if the factory cannot create an object + */ + T create(); + +} diff --git a/src/org/apache/commons/collections4/FactoryUtils.java b/src/org/apache/commons/collections4/FactoryUtils.java new file mode 100644 index 0000000..4ddccd3 --- /dev/null +++ b/src/org/apache/commons/collections4/FactoryUtils.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import org.apache.commons.collections4.functors.ConstantFactory; +import org.apache.commons.collections4.functors.ExceptionFactory; +import org.apache.commons.collections4.functors.InstantiateFactory; +import org.apache.commons.collections4.functors.PrototypeFactory; + +/** + * FactoryUtils provides reference implementations and utilities + * for the Factory functor interface. The supplied factories are: + *

    + *
  • Prototype - clones a specified object + *
  • Instantiate - creates objects using reflection + *
  • Constant - always returns the same object + *
  • Null - always returns null + *
  • Exception - always throws an exception + *
+ *

+ * Since v4.1 only factories which are considered to be unsafe are + * Serializable. Factories considered to be unsafe for serialization are: + *

    + *
  • Prototype + *
  • Instantiate + *
+ * + * @since 3.0 + * @version $Id: FactoryUtils.java 1714362 2015-11-14 20:38:02Z tn $ + */ +public class FactoryUtils { + + /** + * This class is not normally instantiated. + */ + private FactoryUtils() {} + + /** + * Gets a Factory that always throws an exception. + * This could be useful during testing as a placeholder. + * + * @see org.apache.commons.collections4.functors.ExceptionFactory + * + * @param the type that the factory creates + * @return the factory + */ + public static Factory exceptionFactory() { + return ExceptionFactory.exceptionFactory(); + } + + /** + * Gets a Factory that will return null each time the factory is used. + * This could be useful during testing as a placeholder. + * + * @see org.apache.commons.collections4.functors.ConstantFactory + * @param the "type" of null object the factory should return. + * @return the factory + */ + public static Factory nullFactory() { + return ConstantFactory.constantFactory(null); + } + + /** + * Creates a Factory that will return the same object each time the factory + * is used. No check is made that the object is immutable. In general, only + * immutable objects should use the constant factory. Mutable objects should + * use the prototype factory. + * + * @see org.apache.commons.collections4.functors.ConstantFactory + * + * @param the type that the factory creates + * @param constantToReturn the constant object to return each time in the factory + * @return the constant factory. + */ + public static Factory constantFactory(final T constantToReturn) { + return ConstantFactory.constantFactory(constantToReturn); + } + + /** + * Creates a Factory that will return a clone of the same prototype object + * each time the factory is used. The prototype will be cloned using one of these + * techniques (in order): + *
    + *
  • public clone method + *
  • public copy constructor + *
  • serialization clone + *
      + * + * @see org.apache.commons.collections4.functors.PrototypeFactory + * + * @param the type that the factory creates + * @param prototype the object to clone each time in the factory + * @return the prototype factory, or a {@link ConstantFactory#NULL_INSTANCE} if + * the {@code prototype} is {@code null} + * @throws IllegalArgumentException if the prototype cannot be cloned + */ + public static Factory prototypeFactory(final T prototype) { + return PrototypeFactory.prototypeFactory(prototype); + } + + /** + * Creates a Factory that can create objects of a specific type using + * a no-args constructor. + * + * @see org.apache.commons.collections4.functors.InstantiateFactory + * + * @param the type that the factory creates + * @param classToInstantiate the Class to instantiate each time in the factory + * @return the reflection factory + * @throws NullPointerException if the classToInstantiate is null + */ + public static Factory instantiateFactory(final Class classToInstantiate) { + return InstantiateFactory.instantiateFactory(classToInstantiate, null, null); + } + + /** + * Creates a Factory that can create objects of a specific type using + * the arguments specified to this method. + * + * @see org.apache.commons.collections4.functors.InstantiateFactory + * + * @param the type that the factory creates + * @param classToInstantiate the Class to instantiate each time in the factory + * @param paramTypes parameter types for the constructor, can be null + * @param args the arguments to pass to the constructor, can be null + * @return the reflection factory + * @throws NullPointerException if the classToInstantiate is null + * @throws IllegalArgumentException if the paramTypes and args don't match + * @throws IllegalArgumentException if the constructor doesn't exist + */ + public static Factory instantiateFactory(final Class classToInstantiate, final Class[] paramTypes, + final Object[] args) { + return InstantiateFactory.instantiateFactory(classToInstantiate, paramTypes, args); + } + +} diff --git a/src/org/apache/commons/collections4/FluentIterable.java b/src/org/apache/commons/collections4/FluentIterable.java new file mode 100644 index 0000000..1c90606 --- /dev/null +++ b/src/org/apache/commons/collections4/FluentIterable.java @@ -0,0 +1,506 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.collections4.iterators.SingletonIterator; + +/** + * A FluentIterable provides a powerful yet simple API for manipulating + * Iterable instances in a fluent manner. + *

      + * A FluentIterable can be created either from an Iterable or from a set + * of elements. The following types of methods are provided: + *

        + *
      • fluent methods which return a new {@code FluentIterable} instance, + * providing a view of the original iterable (e.g. filter(Predicate)); + *
      • conversion methods which copy the FluentIterable's contents into a + * new collection or array (e.g. toList()); + *
      • utility methods which answer questions about the FluentIterable's + * contents (e.g. size(), anyMatch(Predicate)). + *
      • + *
      + *

      + * The following example outputs the first 3 even numbers in the range [1, 10] + * into a list: + *

      + * List<String> result =
      + *   FluentIterable
      + *       .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
      + *       .filter(new Predicate() {
      + *                   public boolean evaluate(Integer number) {
      + *                        return number % 2 == 0;
      + *                   }
      + *              )
      + *       .transform(TransformerUtils.stringValueTransformer())
      + *       .limit(3)
      + *       .toList();
      + * 
      + * The resulting list will contain the following elements: + *
      [2, 4, 6]
      + * + * @param the element type + * @since 4.1 + * @version $Id: FluentIterable.java 1684264 2015-06-08 20:06:29Z tn $ + */ +public class FluentIterable implements Iterable { + + /** A reference to the wrapped iterable. */ + private final Iterable iterable; + + // Static factory methods + // ---------------------------------------------------------------------- + + /** + * Creates a new empty FluentIterable. + * + * @param the element type + * @return a new empty FluentIterable + */ + @SuppressWarnings("unchecked") + public static FluentIterable empty() { + return IterableUtils.EMPTY_ITERABLE; + } + + /** + * Creates a new FluentIterable of the single provided element. + *

      + * The returned iterable's iterator does not support {@code remove()}. + * + * @param the element type + * @param singleton the singleton element + * @return a new FluentIterable containing the singleton + */ + public static FluentIterable of(final T singleton) { + return of(IteratorUtils.asIterable(new SingletonIterator(singleton, false))); + } + + /** + * Creates a new FluentIterable from the provided elements. + *

      + * The returned iterable's iterator does not support {@code remove()}. + * + * @param the element type + * @param elements the elements to be contained in the FluentIterable + * @return a new FluentIterable containing the provided elements + */ + @SafeVarargs + public static FluentIterable of(final T... elements) { + return of(Arrays.asList(elements)); + } + + /** + * Construct a new FluentIterable from the provided iterable. If the + * iterable is already an instance of FluentIterable, the instance + * will be returned instead. + *

      + * The returned iterable's iterator supports {@code remove()} when the + * corresponding input iterator supports it. + * + * @param the element type + * @param iterable the iterable to wrap into a FluentIterable, may not be null + * @return a new FluentIterable wrapping the provided iterable + * @throws NullPointerException if iterable is null + */ + public static FluentIterable of(final Iterable iterable) { + IterableUtils.checkNotNull(iterable); + if (iterable instanceof FluentIterable) { + return (FluentIterable) iterable; + } else { + return new FluentIterable(iterable); + } + } + + // Constructor + // ---------------------------------------------------------------------- + + /** + * Package-private constructor, used by IterableUtils. + */ + FluentIterable() { + this.iterable = this; + } + + /** + * Create a new FluentIterable by wrapping the provided iterable. + * @param iterable the iterable to wrap + */ + private FluentIterable(final Iterable iterable) { + this.iterable = iterable; + } + + // fluent construction methods + // ---------------------------------------------------------------------- + + /** + * Returns a new FluentIterable whose iterator will first traverse + * the elements of the current iterable, followed by the provided + * elements. + * + * @param elements the elements to append to the iterable + * @return a new iterable, combining this iterable with the elements + */ + public FluentIterable append(@SuppressWarnings("unchecked") final E... elements) { + return append(Arrays.asList(elements)); + } + + /** + * Returns a new FluentIterable whose iterator will first traverse + * the elements of the current iterable, followed by the elements + * of the provided iterable. + * + * @param other the other iterable to combine, may not be null + * @return a new iterable, combining this iterable with other + * @throws NullPointerException if other is null + */ + public FluentIterable append(final Iterable other) { + return of(IterableUtils.chainedIterable(iterable, other)); + } + + /** + * Returns a new FluentIterable whose iterator will traverse the + * elements of the current and provided iterable in natural order. + *

      + * Example: natural ordering + *

        + *
      • this contains elements [1, 3, 5, 7] + *
      • other contains elements [2, 4, 6, 8] + *
      + *

      + * The returned iterable will traverse the elements in the following + * order: [1, 2, 3, 4, 5, 6, 7, 8] + * + * @param other the other iterable to collate, may not be null + * @return a new iterable, collating this iterable with the other in natural order + * @throws NullPointerException if other is null + * @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator} + */ + public FluentIterable collate(final Iterable other) { + return of(IterableUtils.collatedIterable(iterable, other)); + } + + /** + * Returns a new FluentIterable whose iterator will traverse the + * elements of the current and provided iterable according to the + * ordering defined by an comparator. + *

      + * Example: descending order + *

        + *
      • this contains elements [7, 5, 3, 1] + *
      • other contains elements [8, 6, 4, 2] + *
      + *

      + * The returned iterable will traverse the elements in the following + * order: [8, 7, 6, 5, 4, 3, 2, 1] + * + * @param comparator the comparator to define an ordering, may be null, + * in which case natural ordering will be used + * @param other the other iterable to collate, may not be null + * @return a new iterable, collating this iterable with the other in natural order + * @throws NullPointerException if other is null + * @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator} + */ + public FluentIterable collate(final Iterable other, + final Comparator comparator) { + return of(IterableUtils.collatedIterable(comparator, iterable, other)); + } + + /** + * This method fully traverses an iterator of this iterable and returns + * a new iterable with the same contents, but without any reference + * to the originating iterables and/or iterators. + *

      + * Calling this method is equivalent to: + *

      +     *   FluentIterable someIterable = ...;
      +     *   FluentIterable.of(someIterable.toList());
      +     * 
      + * + * @return a new iterable with the same contents as this iterable + */ + public FluentIterable eval() { + return of(toList()); + } + + /** + * Returns a new FluentIterable whose iterator will only return + * elements from this iterable matching the provided predicate. + * + * @param predicate the predicate used to filter elements + * @return a new iterable, providing a filtered view of this iterable + * @throws NullPointerException if predicate is null + */ + public FluentIterable filter(final Predicate predicate) { + return of(IterableUtils.filteredIterable(iterable, predicate)); + } + + /** + * Returns a new FluentIterable whose iterator will return at most + * the provided maximum number of elements from this iterable. + * + * @param maxSize the maximum number of elements + * @return a new iterable, providing a bounded view of this iterable + * @throws IllegalArgumentException if maxSize is negative + */ + public FluentIterable limit(final long maxSize) { + return of(IterableUtils.boundedIterable(iterable, maxSize)); + } + + /** + * Returns a new FluentIterable whose iterator will loop infinitely + * over the elements from this iterable. + * + * @return a new iterable, providing a looping view of this iterable + */ + public FluentIterable loop() { + return of(IterableUtils.loopingIterable(iterable)); + } + + /** + * Returns a new FluentIterable whose iterator will traverse the + * elements from this iterable in reverse order. + * + * @return a new iterable, providing a reversed view of this iterable + */ + public FluentIterable reverse() { + return of(IterableUtils.reversedIterable(iterable)); + } + + /** + * Returns a new FluentIterable whose iterator will skip the first + * N elements from this iterable. + * + * @param elementsToSkip the number of elements to skip + * @return a new iterable, providing a view of this iterable by skipping + * the first N elements + * @throws IllegalArgumentException if elementsToSkip is negative + */ + public FluentIterable skip(final long elementsToSkip) { + return of(IterableUtils.skippingIterable(iterable, elementsToSkip)); + } + + /** + * Returns a new FluentIterable whose iterator will return all elements + * of this iterable transformed by the provided transformer. + * + * @param the output element type + * @param transformer the transformer applied to each element + * @return a new iterable, providing a transformed view of this iterable + * @throws NullPointerException if transformer is null + */ + public FluentIterable transform(final Transformer transformer) { + return of(IterableUtils.transformedIterable(iterable, transformer)); + } + + /** + * Returns a new FluentIterable whose iterator will return a unique view + * of this iterable. + * + * @return a new iterable, providing a unique view of this iterable + */ + public FluentIterable unique() { + return of(IterableUtils.uniqueIterable(iterable)); + } + + /** + * Returns a new FluentIterable whose iterator will return an unmodifiable + * view of this iterable. + * + * @return a new iterable, providing an unmodifiable view of this iterable + */ + public FluentIterable unmodifiable() { + return of(IterableUtils.unmodifiableIterable(iterable)); + } + + /** + * Returns a new FluentIterable whose iterator will traverse + * the elements of this iterable and the other iterable in + * alternating order. + * + * @param other the other iterable to interleave, may not be null + * @return a new iterable, interleaving this iterable with others + * @throws NullPointerException if other is null + */ + public FluentIterable zip(final Iterable other) { + return of(IterableUtils.zippingIterable(iterable, other)); + } + + /** + * Returns a new FluentIterable whose iterator will traverse + * the elements of this iterable and the other iterables in + * alternating order. + * + * @param others the iterables to interleave, may not be null + * @return a new iterable, interleaving this iterable with others + * @throws NullPointerException if either of the provided iterables is null + */ + public FluentIterable zip(@SuppressWarnings("unchecked") final Iterable... others) { + return of(IterableUtils.zippingIterable(iterable, others)); + } + + // convenience methods + // ---------------------------------------------------------------------- + + /** {@inheritDoc} */ + @Override + public Iterator iterator() { + return iterable.iterator(); + } + + /** + * Returns an Enumeration that will enumerate all elements contained + * in this iterable. + * + * @return an Enumeration over the elements of this iterable + */ + public Enumeration asEnumeration() { + return IteratorUtils.asEnumeration(iterator()); + } + + /** + * Checks if all elements contained in this iterable are matching the + * provided predicate. + *

      + * A null or empty iterable returns true. + * + * @param predicate the predicate to use, may not be null + * @return true if all elements contained in this iterable match the predicate, + * false otherwise + * @throws NullPointerException if predicate is null + */ + public boolean allMatch(final Predicate predicate) { + return IterableUtils.matchesAll(iterable, predicate); + } + + /** + * Checks if this iterable contains any element matching the provided predicate. + *

      + * A null or empty iterable returns false. + * + * @param predicate the predicate to use, may not be null + * @return true if at least one element contained in this iterable matches the predicate, + * false otherwise + * @throws NullPointerException if predicate is null + */ + public boolean anyMatch(final Predicate predicate) { + return IterableUtils.matchesAny(iterable, predicate); + } + + /** + * Checks if this iterable is empty. + * + * @return true if this iterable does not contain any elements, false otherwise + */ + public boolean isEmpty() { + return IterableUtils.isEmpty(iterable); + } + + /** + * Checks if the object is contained in this iterable. + * + * @param object the object to check + * @return true if the object is contained in this iterable, false otherwise + */ + public boolean contains(final Object object) { + return IterableUtils.contains(iterable, object); + } + + /** + * Applies the closure to all elements contained in this iterable. + * + * @param closure the closure to apply to each element, may not be null + * @throws NullPointerException if closure is null + */ + public void forEach(final Closure closure) { + IterableUtils.forEach(iterable, closure); + } + + /** + * Returns the element at the provided position in this iterable. + * In order to return the element, an iterator needs to be traversed + * up to the requested position. + * + * @param position the position of the element to return + * @return the element + * @throws IndexOutOfBoundsException if the provided position is outside the + * valid range of this iterable: [0, size) + */ + public E get(final int position) { + return IterableUtils.get(iterable, position); + } + + /** + * Returns the number of elements that are contained in this iterable. + * In order to determine the size, an iterator needs to be traversed. + * + * @return the size of this iterable + */ + public int size() { + return IterableUtils.size(iterable); + } + + /** + * Traverses an iterator of this iterable and adds all elements + * to the provided collection. + * + * @param collection the collection to add the elements + * @throws NullPointerException if collection is null + */ + public void copyInto(final Collection collection) { + if (collection == null) { + throw new NullPointerException("Collection must not be null"); + } + CollectionUtils.addAll(collection, iterable); + } + + /** + * Returns an array containing all elements of this iterable by traversing + * its iterator. + * + * @param arrayClass the class of array to create + * @return an array of the iterable contents + * @throws ArrayStoreException if arrayClass is invalid + */ + public E[] toArray(final Class arrayClass) { + return IteratorUtils.toArray(iterator(), arrayClass); + } + + /** + * Returns a mutable list containing all elements of this iterable + * by traversing its iterator. + *

      + * The returned list is guaranteed to be mutable. + * + * @return a list of the iterable contents + */ + public List toList() { + return IterableUtils.toList(iterable); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return IterableUtils.toString(iterable); + } + +} diff --git a/src/org/apache/commons/collections4/FunctorException.java b/src/org/apache/commons/collections4/FunctorException.java new file mode 100644 index 0000000..5b0406e --- /dev/null +++ b/src/org/apache/commons/collections4/FunctorException.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Runtime exception thrown from functors. + * If required, a root cause error can be wrapped within this one. + * + * @since 3.0 + * @version $Id: FunctorException.java 1477779 2013-04-30 18:55:24Z tn $ + */ +public class FunctorException extends RuntimeException { + + /** Serialization version */ + private static final long serialVersionUID = -4704772662059351193L; + + /** + * Constructs a new FunctorException without specified + * detail message. + */ + public FunctorException() { + super(); + } + + /** + * Constructs a new FunctorException with specified + * detail message. + * + * @param msg the error message. + */ + public FunctorException(final String msg) { + super(msg); + } + + /** + * Constructs a new FunctorException with specified + * nested Throwable root cause. + * + * @param rootCause the exception or error that caused this exception + * to be thrown. + */ + public FunctorException(final Throwable rootCause) { + super(rootCause); + } + + /** + * Constructs a new FunctorException with specified + * detail message and nested Throwable root cause. + * + * @param msg the error message. + * @param rootCause the exception or error that caused this exception + * to be thrown. + */ + public FunctorException(final String msg, final Throwable rootCause) { + super(msg, rootCause); + } + +} diff --git a/src/org/apache/commons/collections4/Get.java b/src/org/apache/commons/collections4/Get.java new file mode 100644 index 0000000..150c8d2 --- /dev/null +++ b/src/org/apache/commons/collections4/Get.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Set; + +/** + * The "read" subset of the {@link java.util.Map} interface. + * + * @since 4.0 + * @version $Id: Get.java 1543265 2013-11-19 00:48:44Z ggregory $ + * + * @see Put + */ +public interface Get { + + /** + * @see java.util.Map#containsKey(Object) + */ + boolean containsKey(Object key); + + /** + * @see java.util.Map#containsValue(Object) + */ + boolean containsValue(Object value); + + /** + * @see java.util.Map#entrySet() + */ + Set> entrySet(); + + /** + * @see java.util.Map#get(Object) + */ + V get(Object key); + + /** + * @see java.util.Map#remove(Object) + */ + V remove(Object key); + + /** + * @see java.util.Map#isEmpty() + */ + boolean isEmpty(); + + /** + * @see java.util.Map#keySet() + */ + Set keySet(); + + /** + * @see java.util.Map#size() + */ + int size(); + + /** + * @see java.util.Map#values() + */ + Collection values(); + +} diff --git a/src/org/apache/commons/collections4/IterableGet.java b/src/org/apache/commons/collections4/IterableGet.java new file mode 100644 index 0000000..2035dd2 --- /dev/null +++ b/src/org/apache/commons/collections4/IterableGet.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * The "read" subset of the {@link java.util.Map} interface. + * + * @since 4.0 + * @version $Id: IterableGet.java 1477779 2013-04-30 18:55:24Z tn $ + * + * @see Put + */ +public interface IterableGet extends Get { + /** + * Obtains a MapIterator over the map. + *

      + * A map iterator is an efficient way of iterating over maps. + * There is no need to access the entry set or use Map Entry objects. + *

      +     * IterableMap map = new HashedMap();
      +     * MapIterator it = map.mapIterator();
      +     * while (it.hasNext()) {
      +     *   String key = it.next();
      +     *   Integer value = it.getValue();
      +     *   it.setValue(value + 1);
      +     * }
      +     * 
      + * + * @return a map iterator + */ + MapIterator mapIterator(); + +} diff --git a/src/org/apache/commons/collections4/IterableMap.java b/src/org/apache/commons/collections4/IterableMap.java new file mode 100644 index 0000000..c9ab72d --- /dev/null +++ b/src/org/apache/commons/collections4/IterableMap.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Map; + +/** + * Defines a map that can be iterated directly without needing to create an entry set. + *

      + * A map iterator is an efficient way of iterating over maps. + * There is no need to access the entry set or use Map Entry objects. + *

      + * IterableMap map = new HashedMap();
      + * MapIterator it = map.mapIterator();
      + * while (it.hasNext()) {
      + *   String key = it.next();
      + *   Integer value = it.getValue();
      + *   it.setValue(value + 1);
      + * }
      + * 
      + * + * @param the type of the keys in the map + * @param the type of the values in the map + * + * @since 3.0 + * @version $Id: IterableMap.java 1469004 2013-04-17 17:37:03Z tn $ + */ +public interface IterableMap extends Map, Put, IterableGet { +} diff --git a/src/org/apache/commons/collections4/IterableSortedMap.java b/src/org/apache/commons/collections4/IterableSortedMap.java new file mode 100644 index 0000000..a39a508 --- /dev/null +++ b/src/org/apache/commons/collections4/IterableSortedMap.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.SortedMap; + +/** + * {@link SortedMap} + {@link OrderedMap}. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * + * @since 4.0 + * @version $Id: IterableSortedMap.java 1469004 2013-04-17 17:37:03Z tn $ + */ +public interface IterableSortedMap extends SortedMap, OrderedMap { +} diff --git a/src/org/apache/commons/collections4/IterableUtils.java b/src/org/apache/commons/collections4/IterableUtils.java new file mode 100644 index 0000000..e504043 --- /dev/null +++ b/src/org/apache/commons/collections4/IterableUtils.java @@ -0,0 +1,1090 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.commons.collections4.functors.EqualPredicate; +import org.apache.commons.collections4.iterators.LazyIteratorChain; +import org.apache.commons.collections4.iterators.ReverseListIterator; +import org.apache.commons.collections4.iterators.UniqueFilterIterator; + +/** + * Provides utility methods and decorators for {@link Iterable} instances. + *

      + * Note: this util class has been designed for fail-fast argument checking. + *

        + *
      • + * all decorator methods are NOT null-safe wrt the provided Iterable argument, i.e. + * they will throw a {@link NullPointerException} if a null Iterable is passed as argument. + *
      • + * all other utility methods are null-safe wrt the provided Iterable argument, i.e. they will + * treat a null Iterable the same way as an empty one. Other arguments which are null, + * e.g. a {@link Predicate}, will result in a {@link NullPointerException}. Exception: passing + * a null {@link Comparator} is equivalent to a Comparator with natural ordering. + *
      + * + * @since 4.1 + * @version $Id: IterableUtils.java 1716538 2015-11-25 20:27:49Z tn $ + */ +public class IterableUtils { + + /** + * An empty iterable. + */ + @SuppressWarnings("rawtypes") + static final FluentIterable EMPTY_ITERABLE = new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.emptyIterator(); + } + }; + + // Empty + // ---------------------------------------------------------------------- + + /** + * Gets an empty iterable. + *

      + * This iterable does not contain any elements. + * + * @param the element type + * @return an empty iterable + */ + @SuppressWarnings("unchecked") // OK, empty collection is compatible with any type + public static Iterable emptyIterable() { + return EMPTY_ITERABLE; + } + + // Chained + // ---------------------------------------------------------------------- + + /** + * Combines two iterables into a single iterable. + *

      + * The returned iterable has an iterator that traverses the elements in {@code a}, + * followed by the elements in {@code b}. The source iterators are not polled until + * necessary. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param a the first iterable, may not be null + * @param b the second iterable, may not be null + * @return a new iterable, combining the provided iterables + * @throws NullPointerException if either a or b is null + */ + @SuppressWarnings("unchecked") + public static Iterable chainedIterable(final Iterable a, + final Iterable b) { + return chainedIterable(new Iterable[] {a, b}); + } + + /** + * Combines three iterables into a single iterable. + *

      + * The returned iterable has an iterator that traverses the elements in {@code a}, + * followed by the elements in {@code b} and {@code c}. The source iterators are + * not polled until necessary. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param a the first iterable, may not be null + * @param b the second iterable, may not be null + * @param c the third iterable, may not be null + * @return a new iterable, combining the provided iterables + * @throws NullPointerException if either of the provided iterables is null + */ + @SuppressWarnings("unchecked") + public static Iterable chainedIterable(final Iterable a, + final Iterable b, + final Iterable c) { + return chainedIterable(new Iterable[] {a, b, c}); + } + + /** + * Combines four iterables into a single iterable. + *

      + * The returned iterable has an iterator that traverses the elements in {@code a}, + * followed by the elements in {@code b}, {@code c} and {@code d}. The source + * iterators are not polled until necessary. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param a the first iterable, may not be null + * @param b the second iterable, may not be null + * @param c the third iterable, may not be null + * @param d the fourth iterable, may not be null + * @return a new iterable, combining the provided iterables + * @throws NullPointerException if either of the provided iterables is null + */ + @SuppressWarnings("unchecked") + public static Iterable chainedIterable(final Iterable a, + final Iterable b, + final Iterable c, + final Iterable d) { + return chainedIterable(new Iterable[] {a, b, c, d}); + } + + /** + * Combines the provided iterables into a single iterable. + *

      + * The returned iterable has an iterator that traverses the elements in the order + * of the arguments, i.e. iterables[0], iterables[1], .... The source iterators + * are not polled until necessary. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param iterables the iterables to combine, may not be null + * @return a new iterable, combining the provided iterables + * @throws NullPointerException if either of the provided iterables is null + */ + @SafeVarargs + public static Iterable chainedIterable(final Iterable... iterables) { + checkNotNull(iterables); + return new FluentIterable() { + @Override + public Iterator iterator() { + return new LazyIteratorChain() { + @Override + protected Iterator nextIterator(int count) { + if (count > iterables.length) { + return null; + } else { + return iterables[count - 1].iterator(); + } + } + }; + } + }; + } + + // Collated + // ---------------------------------------------------------------------- + + /** + * Combines the two provided iterables into an ordered iterable using + * natural ordering. + *

      + * The returned iterable's iterator supports {@code remove()} when the + * corresponding input iterator supports it. + * + * @param the element type + * @param a the first iterable, may not be null + * @param b the second iterable, may not be null + * @return a filtered view on the specified iterable + * @throws NullPointerException if either of the provided iterables is null + */ + public static Iterable collatedIterable(final Iterable a, + final Iterable b) { + checkNotNull(a, b); + return new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.collatedIterator(null, a.iterator(), b.iterator()); + } + }; + } + + /** + * Combines the two provided iterables into an ordered iterable using the + * provided comparator. If the comparator is null, natural ordering will be + * used. + *

      + * The returned iterable's iterator supports {@code remove()} when the + * corresponding input iterator supports it. + * + * @param the element type + * @param comparator the comparator defining an ordering over the elements, + * may be null, in which case natural ordering will be used + * @param a the first iterable, may not be null + * @param b the second iterable, may not be null + * @return a filtered view on the specified iterable + * @throws NullPointerException if either of the provided iterables is null + */ + public static Iterable collatedIterable(final Comparator comparator, + final Iterable a, + final Iterable b) { + checkNotNull(a, b); + return new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.collatedIterator(comparator, a.iterator(), b.iterator()); + } + }; + } + + // Filtered + // ---------------------------------------------------------------------- + + /** + * Returns a view of the given iterable that only contains elements matching + * the provided predicate. + *

      + * The returned iterable's iterator supports {@code remove()} when the + * corresponding input iterator supports it. + * + * @param the element type + * @param iterable the iterable to filter, may not be null + * @param predicate the predicate used to filter elements, may not be null + * @return a filtered view on the specified iterable + * @throws NullPointerException if either iterable or predicate is null + */ + public static Iterable filteredIterable(final Iterable iterable, + final Predicate predicate) { + checkNotNull(iterable); + if (predicate == null) { + throw new NullPointerException("Predicate must not be null."); + } + return new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.filteredIterator(emptyIteratorIfNull(iterable), predicate); + } + }; + } + + // Bounded + // ---------------------------------------------------------------------- + + /** + * Returns a view of the given iterable that contains at most the given number + * of elements. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param iterable the iterable to limit, may not be null + * @param maxSize the maximum number of elements, must not be negative + * @return a bounded view on the specified iterable + * @throws IllegalArgumentException if maxSize is negative + * @throws NullPointerException if iterable is null + */ + public static Iterable boundedIterable(final Iterable iterable, final long maxSize) { + checkNotNull(iterable); + if (maxSize < 0) { + throw new IllegalArgumentException("MaxSize parameter must not be negative."); + } + + return new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.boundedIterator(iterable.iterator(), maxSize); + } + }; + } + + // Looping + // ---------------------------------------------------------------------- + + /** + * Returns a view of the given iterable which will cycle infinitely over + * its elements. + *

      + * The returned iterable's iterator supports {@code remove()} if + * {@code iterable.iterator()} does. After {@code remove()} is called, subsequent + * cycles omit the removed element, which is no longer in {@code iterable}. The + * iterator's {@code hasNext()} method returns {@code true} until {@code iterable} + * is empty. + * + * @param the element type + * @param iterable the iterable to loop, may not be null + * @return a view of the iterable, providing an infinite loop over its elements + * @throws NullPointerException if iterable is null + */ + public static Iterable loopingIterable(final Iterable iterable) { + checkNotNull(iterable); + return new FluentIterable() { + @Override + public Iterator iterator() { + return new LazyIteratorChain() { + @Override + protected Iterator nextIterator(int count) { + if (IterableUtils.isEmpty(iterable)) { + return null; + } else { + return iterable.iterator(); + } + } + }; + } + }; + } + + // Reversed + // ---------------------------------------------------------------------- + + /** + * Returns a reversed view of the given iterable. + *

      + * In case the provided iterable is a {@link List} instance, a + * {@link ReverseListIterator} will be used to reverse the traversal + * order, otherwise an intermediate {@link List} needs to be created. + *

      + * The returned iterable's iterator supports {@code remove()} if the + * provided iterable is a {@link List} instance. + * + * @param the element type + * @param iterable the iterable to use, may not be null + * @return a reversed view of the specified iterable + * @throws NullPointerException if iterable is null + * @see ReverseListIterator + */ + public static Iterable reversedIterable(final Iterable iterable) { + checkNotNull(iterable); + return new FluentIterable() { + @Override + public Iterator iterator() { + final List list = (iterable instanceof List) ? + (List) iterable : + IteratorUtils.toList(iterable.iterator()); + return new ReverseListIterator(list); + } + }; + } + + // Skipping + // ---------------------------------------------------------------------- + + /** + * Returns a view of the given iterable that skips the first N elements. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param iterable the iterable to use, may not be null + * @param elementsToSkip the number of elements to skip from the start, must not be negative + * @return a view of the specified iterable, skipping the first N elements + * @throws IllegalArgumentException if elementsToSkip is negative + * @throws NullPointerException if iterable is null + */ + public static Iterable skippingIterable(final Iterable iterable, final long elementsToSkip) { + checkNotNull(iterable); + if (elementsToSkip < 0) { + throw new IllegalArgumentException("ElementsToSkip parameter must not be negative."); + } + + return new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.skippingIterator(iterable.iterator(), elementsToSkip); + } + }; + } + + // Transformed + // ---------------------------------------------------------------------- + + /** + * Returns a transformed view of the given iterable where all of its elements + * have been transformed by the provided transformer. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the input element type + * @param the output element type + * @param iterable the iterable to transform, may not be null + * @param transformer the transformer, must not be null + * @return a transformed view of the specified iterable + * @throws NullPointerException if either iterable or transformer is null + */ + public static Iterable transformedIterable(final Iterable iterable, + final Transformer transformer) { + checkNotNull(iterable); + if (transformer == null) { + throw new NullPointerException("Transformer must not be null."); + } + return new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.transformedIterator(iterable.iterator(), transformer); + } + }; + } + + // Unique + // ---------------------------------------------------------------------- + + /** + * Returns a unique view of the given iterable. + *

      + * The returned iterable's iterator supports {@code remove()} when the + * corresponding input iterator supports it. Calling {@code remove()} + * will only remove a single element from the underlying iterator. + * + * @param the element type + * @param iterable the iterable to use, may not be null + * @return a unique view of the specified iterable + * @throws NullPointerException if iterable is null + */ + public static Iterable uniqueIterable(final Iterable iterable) { + checkNotNull(iterable); + return new FluentIterable() { + @Override + public Iterator iterator() { + return new UniqueFilterIterator(iterable.iterator()); + } + }; + } + + // Unmodifiable + // ---------------------------------------------------------------------- + + /** + * Returns an unmodifiable view of the given iterable. + *

      + * The returned iterable's iterator does not support {@code remove()}. + * + * @param the element type + * @param iterable the iterable to use, may not be null + * @return an unmodifiable view of the specified iterable + * @throws NullPointerException if iterable is null + */ + public static Iterable unmodifiableIterable(final Iterable iterable) { + checkNotNull(iterable); + if (iterable instanceof UnmodifiableIterable) { + return iterable; + } + return new UnmodifiableIterable(iterable); + } + + /** + * Inner class to distinguish unmodifiable instances. + */ + private static final class UnmodifiableIterable extends FluentIterable { + private final Iterable unmodifiable; + + public UnmodifiableIterable(final Iterable iterable) { + super(); + this.unmodifiable = iterable; + } + + @Override + public Iterator iterator() { + return IteratorUtils.unmodifiableIterator(unmodifiable.iterator()); + } + } + + // Zipping + // ---------------------------------------------------------------------- + + /** + * Interleaves two iterables into a single iterable. + *

      + * The returned iterable has an iterator that traverses the elements in {@code a} + * and {@code b} in alternating order. The source iterators are not polled until + * necessary. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param a the first iterable, may not be null + * @param b the second iterable, may not be null + * @return a new iterable, interleaving the provided iterables + * @throws NullPointerException if either a or b is null + */ + public static Iterable zippingIterable(final Iterable a, + final Iterable b) { + checkNotNull(a); + checkNotNull(b); + return new FluentIterable() { + @Override + public Iterator iterator() { + return IteratorUtils.zippingIterator(a.iterator(), b.iterator()); + } + }; + } + + /** + * Interleaves two iterables into a single iterable. + *

      + * The returned iterable has an iterator that traverses the elements in {@code a} + * and {@code b} in alternating order. The source iterators are not polled until + * necessary. + *

      + * The returned iterable's iterator supports {@code remove()} when the corresponding + * input iterator supports it. + * + * @param the element type + * @param first the first iterable, may not be null + * @param others the array of iterables to interleave, may not be null + * @return a new iterable, interleaving the provided iterables + * @throws NullPointerException if either of the provided iterables is null + */ + @SafeVarargs + public static Iterable zippingIterable(final Iterable first, + final Iterable... others) { + checkNotNull(first); + checkNotNull(others); + return new FluentIterable() { + @Override + public Iterator iterator() { + @SuppressWarnings("unchecked") // safe + Iterator[] iterators = new Iterator[others.length + 1]; + iterators[0] = first.iterator(); + for (int i = 0; i < others.length; i++) { + iterators[i + 1] = others[i].iterator(); + } + return IteratorUtils.zippingIterator(iterators); + } + }; + } + + // Utility methods + // ---------------------------------------------------------------------- + + /** + * Returns an immutable empty iterable if the argument is null, + * or the argument itself otherwise. + * + * @param the element type + * @param iterable the iterable, may be null + * @return an empty iterable if the argument is null + */ + public static Iterable emptyIfNull(final Iterable iterable) { + return iterable == null ? IterableUtils.emptyIterable() : iterable; + } + + /** + * Applies the closure to each element of the provided iterable. + * + * @param the element type + * @param iterable the iterator to use, may be null + * @param closure the closure to apply to each element, may not be null + * @throws NullPointerException if closure is null + */ + public static void forEach(final Iterable iterable, final Closure closure) { + IteratorUtils.forEach(emptyIteratorIfNull(iterable), closure); + } + + /** + * Executes the given closure on each but the last element in the iterable. + *

      + * If the input iterable is null no change is made. + * + * @param the type of object the {@link Iterable} contains + * @param iterable the iterable to get the input from, may be null + * @param closure the closure to perform, may not be null + * @return the last element in the iterable, or null if iterable is null or empty + */ + public static E forEachButLast(final Iterable iterable, final Closure closure) { + return IteratorUtils.forEachButLast(emptyIteratorIfNull(iterable), closure); + } + + /** + * Finds the first element in the given iterable which matches the given predicate. + *

      + * A null or empty iterator returns null. + * + * @param the element type + * @param iterable the iterable to search, may be null + * @param predicate the predicate to use, may not be null + * @return the first element of the iterable which matches the predicate or null if none could be found + * @throws NullPointerException if predicate is null + */ + public static E find(final Iterable iterable, final Predicate predicate) { + return IteratorUtils.find(emptyIteratorIfNull(iterable), predicate); + } + + /** + * Returns the index of the first element in the specified iterable that + * matches the given predicate. + *

      + * A null or empty iterable returns -1. + * + * @param the element type + * @param iterable the iterable to search, may be null + * @param predicate the predicate to use, may not be null + * @return the index of the first element which matches the predicate or -1 if none matches + * @throws NullPointerException if predicate is null + */ + public static int indexOf(final Iterable iterable, final Predicate predicate) { + return IteratorUtils.indexOf(emptyIteratorIfNull(iterable), predicate); + } + + /** + * Answers true if a predicate is true for every element of an iterable. + *

      + * A null or empty iterable returns true. + * + * @param the type of object the {@link Iterable} contains + * @param iterable the {@link Iterable} to use, may be null + * @param predicate the predicate to use, may not be null + * @return true if every element of the collection matches the predicate or if the + * collection is empty, false otherwise + * @throws NullPointerException if predicate is null + */ + public static boolean matchesAll(final Iterable iterable, final Predicate predicate) { + return IteratorUtils.matchesAll(emptyIteratorIfNull(iterable), predicate); + } + + /** + * Answers true if a predicate is true for any element of the iterable. + *

      + * A null or empty iterable returns false. + * + * @param the type of object the {@link Iterable} contains + * @param iterable the {@link Iterable} to use, may be null + * @param predicate the predicate to use, may not be null + * @return true if any element of the collection matches the predicate, false otherwise + * @throws NullPointerException if predicate is null + */ + public static boolean matchesAny(final Iterable iterable, final Predicate predicate) { + return IteratorUtils.matchesAny(emptyIteratorIfNull(iterable), predicate); + } + + /** + * Counts the number of elements in the input iterable that match the predicate. + *

      + * A null iterable matches no elements. + * + * @param the type of object the {@link Iterable} contains + * @param input the {@link Iterable} to get the input from, may be null + * @param predicate the predicate to use, may not be null + * @return the number of matches for the predicate in the collection + * @throws NullPointerException if predicate is null + */ + public static long countMatches(final Iterable input, final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null."); + } + return size(filteredIterable(emptyIfNull(input), predicate)); + } + + /** + * Answers true if the provided iterable is empty. + *

      + * A null iterable returns true. + * + * @param iterable the {@link Iterable to use}, may be null + * @return true if the iterable is null or empty, false otherwise + */ + public static boolean isEmpty(final Iterable iterable) { + if (iterable instanceof Collection) { + return ((Collection) iterable).isEmpty(); + } else { + return IteratorUtils.isEmpty(emptyIteratorIfNull(iterable)); + } + } + + /** + * Checks if the object is contained in the given iterable. + *

      + * A null or empty iterable returns false. + * + * @param the type of object the {@link Iterable} contains + * @param iterable the iterable to check, may be null + * @param object the object to check + * @return true if the object is contained in the iterable, false otherwise + */ + public static boolean contains(final Iterable iterable, final Object object) { + if (iterable instanceof Collection) { + return ((Collection) iterable).contains(object); + } else { + return IteratorUtils.contains(emptyIteratorIfNull(iterable), object); + } + } + + /** + * Checks if the object is contained in the given iterable. Object equality + * is tested with an {@code equator} unlike {@link #contains(Iterable, Object)} + * which uses {@link Object#equals(Object)}. + *

      + * A null or empty iterable returns false. + * A null object will not be passed to the equator, instead a + * {@link org.apache.commons.collections4.functors.NullPredicate NullPredicate} + * will be used. + * + * @param the type of object the {@link Iterable} contains + * @param iterable the iterable to check, may be null + * @param object the object to check + * @param equator the equator to use to check, may not be null + * @return true if the object is contained in the iterable, false otherwise + * @throws NullPointerException if equator is null + */ + public static boolean contains(final Iterable iterable, final E object, + final Equator equator) { + if (equator == null) { + throw new NullPointerException("Equator must not be null."); + } + return matchesAny(iterable, EqualPredicate.equalPredicate(object, equator)); + } + + /** + * Returns the number of occurrences of the provided object in the iterable. + * + * @param the element type that the {@link Iterable} may contain + * @param the element type of the object to find + * @param iterable the {@link Iterable} to search + * @param obj the object to find the cardinality of + * @return the the number of occurrences of obj in iterable + */ + public static int frequency(final Iterable iterable, final T obj) { + if (iterable instanceof Set) { + return ((Set) iterable).contains(obj) ? 1 : 0; + } + if (iterable instanceof Bag) { + return ((Bag) iterable).getCount(obj); + } + return size(filteredIterable(emptyIfNull(iterable), EqualPredicate.equalPredicate(obj))); + } + + /** + * Returns the index-th value in the iterable's {@link Iterator}, throwing + * IndexOutOfBoundsException if there is no such element. + *

      + * If the {@link Iterable} is a {@link List}, then it will use {@link List#get(int)}. + * + * @param the type of object in the {@link Iterable}. + * @param iterable the {@link Iterable} to get a value from, may be null + * @param index the index to get + * @return the object at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public static T get(final Iterable iterable, final int index) { + CollectionUtils.checkIndexBounds(index); + if (iterable instanceof List) { + return ((List) iterable).get(index); + } + return IteratorUtils.get(emptyIteratorIfNull(iterable), index); + } + + /** + * Returns the number of elements contained in the given iterator. + *

      + * A null or empty iterator returns {@code 0}. + * + * @param iterable the iterable to check, may be null + * @return the number of elements contained in the iterable + */ + public static int size(final Iterable iterable) { + if (iterable instanceof Collection) { + return ((Collection) iterable).size(); + } else { + return IteratorUtils.size(emptyIteratorIfNull(iterable)); + } + } + + /** + * Partitions all elements from iterable into separate output collections, + * based on the evaluation of the given predicate. + *

      + * For each predicate, the result will contain a list holding all elements of the + * input iterable matching the predicate. The last list will hold all elements + * which didn't match any predicate: + *

      +     *  [C1, R] = partition(I, P1) with
      +     *  I = input
      +     *  P1 = first predicate
      +     *  C1 = collection of elements matching P1
      +     *  R = collection of elements rejected by all predicates
      +     * 
      + *

      + * If the input iterable is null, the same is returned as for an + * empty iterable. + *

      + * Example: for an input list [1, 2, 3, 4, 5] calling partition with a predicate [x < 3] + * will result in the following output: [[1, 2], [3, 4, 5]]. + * + * @param the type of object the {@link Iterable} contains + * @param iterable the iterable to partition, may be null + * @param predicate the predicate to use, may not be null + * @return a list containing the output collections + * @throws NullPointerException if predicate is null + */ + public static List> partition(final Iterable iterable, + final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null."); + } + @SuppressWarnings({ "unchecked", "rawtypes" }) // safe + final Factory> factory = FactoryUtils.instantiateFactory((Class) ArrayList.class); + @SuppressWarnings("unchecked") // safe + final Predicate[] predicates = new Predicate[] { predicate }; + return partition(iterable, factory, predicates); + } + + /** + * Partitions all elements from iterable into separate output collections, + * based on the evaluation of the given predicates. + *

      + * For each predicate, the result will contain a list holding all elements of the + * input iterable matching the predicate. The last list will hold all elements + * which didn't match any predicate: + *

      +     *  [C1, C2, R] = partition(I, P1, P2) with
      +     *  I = input
      +     *  P1 = first predicate
      +     *  P2 = second predicate
      +     *  C1 = collection of elements matching P1
      +     *  C2 = collection of elements matching P2
      +     *  R = collection of elements rejected by all predicates
      +     * 
      + *

      + * Note: elements are only added to the output collection of the first matching + * predicate, determined by the order of arguments. + *

      + * If the input iterable is null, the same is returned as for an + * empty iterable. + *

      + * Example: for an input list [1, 2, 3, 4, 5] calling partition with predicates [x < 3] + * and [x < 5] will result in the following output: [[1, 2], [3, 4], [5]]. + * + * @param the type of object the {@link Iterable} contains + * @param iterable the collection to get the input from, may be null + * @param predicates the predicates to use, may not be null + * @return a list containing the output collections + * @throws NullPointerException if any predicate is null + */ + @SafeVarargs + public static List> partition(final Iterable iterable, + final Predicate... predicates) { + + @SuppressWarnings({ "unchecked", "rawtypes" }) // safe + final Factory> factory = FactoryUtils.instantiateFactory((Class) ArrayList.class); + return partition(iterable, factory, predicates); + } + + /** + * Partitions all elements from iterable into separate output collections, + * based on the evaluation of the given predicates. + *

      + * For each predicate, the returned list will contain a collection holding + * all elements of the input iterable matching the predicate. The last collection + * contained in the list will hold all elements which didn't match any predicate: + *

      +     *  [C1, C2, R] = partition(I, P1, P2) with
      +     *  I = input
      +     *  P1 = first predicate
      +     *  P2 = second predicate
      +     *  C1 = collection of elements matching P1
      +     *  C2 = collection of elements matching P2
      +     *  R = collection of elements rejected by all predicates
      +     * 
      + *

      + * Note: elements are only added to the output collection of the first matching + * predicate, determined by the order of arguments. + *

      + * If the input iterable is null, the same is returned as for an + * empty iterable. + * If no predicates have been provided, all elements of the input collection + * will be added to the rejected collection. + *

      + * Example: for an input list [1, 2, 3, 4, 5] calling partition with predicates [x < 3] + * and [x < 5] will result in the following output: [[1, 2], [3, 4], [5]]. + * + * @param the type of object the {@link Iterable} contains + * @param the type of the output {@link Collection} + * @param iterable the collection to get the input from, may be null + * @param partitionFactory the factory used to create the output collections + * @param predicates the predicates to use, may not be null + * @return a list containing the output collections + * @throws NullPointerException if any predicate is null + */ + @SafeVarargs + public static > List partition(final Iterable iterable, + final Factory partitionFactory, final Predicate... predicates) { + + if (iterable == null) { + final Iterable empty = emptyIterable(); + return partition(empty, partitionFactory, predicates); + } + + if (predicates == null) { + throw new NullPointerException("Predicates must not be null."); + } + + for (Predicate p : predicates) { + if (p == null) { + throw new NullPointerException("Predicate must not be null."); + } + } + + if (predicates.length < 1) { + // return the entire input collection as a single partition + final R singlePartition = partitionFactory.create(); + CollectionUtils.addAll(singlePartition, iterable); + return Collections.singletonList(singlePartition); + } + + // create the empty partitions + final int numberOfPredicates = predicates.length; + final int numberOfPartitions = numberOfPredicates + 1; + final List partitions = new ArrayList(numberOfPartitions); + for (int i = 0; i < numberOfPartitions; ++i) { + partitions.add(partitionFactory.create()); + } + + // for each element in inputCollection: + // find the first predicate that evaluates to true. + // if there is a predicate, add the element to the corresponding partition. + // if there is no predicate, add it to the last, catch-all partition. + for (final O element : iterable) { + boolean elementAssigned = false; + for (int i = 0; i < numberOfPredicates; ++i) { + if (predicates[i].evaluate(element)) { + partitions.get(i).add(element); + elementAssigned = true; + break; + } + } + + if (!elementAssigned) { + // no predicates evaluated to true + // add element to last partition + partitions.get(numberOfPredicates).add(element); + } + } + + return partitions; + } + + /** + * Gets a new list with the contents of the provided iterable. + * + * @param the element type + * @param iterable the iterable to use, may be null + * @return a list of the iterator contents + */ + public static List toList(final Iterable iterable) { + return IteratorUtils.toList(emptyIteratorIfNull(iterable)); + } + + /** + * Returns a string representation of the elements of the specified iterable. + *

      + * The string representation consists of a list of the iterable's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated + * by the characters {@code ", "} (a comma followed by a space). Elements are + * converted to strings as by {@code String.valueOf(Object)}. + * + * @param the element type + * @param iterable the iterable to convert to a string, may be null + * @return a string representation of {@code iterable} + */ + public static String toString(final Iterable iterable) { + return IteratorUtils.toString(emptyIteratorIfNull(iterable)); + } + + /** + * Returns a string representation of the elements of the specified iterable. + *

      + * The string representation consists of a list of the iterable's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated + * by the characters {@code ", "} (a comma followed by a space). Elements are + * converted to strings as by using the provided {@code transformer}. + * + * @param the element type + * @param iterable the iterable to convert to a string, may be null + * @param transformer the transformer used to get a string representation of an element + * @return a string representation of {@code iterable} + * @throws NullPointerException if {@code transformer} is null + */ + public static String toString(final Iterable iterable, + final Transformer transformer) { + if (transformer == null) { + throw new NullPointerException("Transformer must not be null."); + } + return IteratorUtils.toString(emptyIteratorIfNull(iterable), transformer); + } + + /** + * Returns a string representation of the elements of the specified iterable. + *

      + * The string representation consists of a list of the iterable's elements, + * enclosed by the provided {@code prefix} and {@code suffix}. Adjacent elements + * are separated by the provided {@code delimiter}. Elements are converted to + * strings as by using the provided {@code transformer}. + * + * @param the element type + * @param iterable the iterable to convert to a string, may be null + * @param transformer the transformer used to get a string representation of an element + * @param delimiter the string to delimit elements + * @param prefix the prefix, prepended to the string representation + * @param suffix the suffix, appended to the string representation + * @return a string representation of {@code iterable} + * @throws NullPointerException if either transformer, delimiter, prefix or suffix is null + */ + public static String toString(final Iterable iterable, + final Transformer transformer, + final String delimiter, + final String prefix, + final String suffix) { + return IteratorUtils.toString(emptyIteratorIfNull(iterable), + transformer, delimiter, prefix, suffix); + } + + // Helper methods + // ---------------------------------------------------------------------- + + /** + * Fail-fast check for null arguments. + * + * @param iterable the iterable to check + * @throws NullPointerException if iterable is null + */ + static void checkNotNull(final Iterable iterable) { + if (iterable == null) { + throw new NullPointerException("Iterable must not be null."); + } + } + + /** + * Fail-fast check for null arguments. + * + * @param iterable the iterable to check + * @throws NullPointerException if the argument or any of its contents is null + */ + static void checkNotNull(final Iterable... iterables) { + if (iterables == null) { + throw new NullPointerException("Iterables must not be null."); + } + for (final Iterable iterable : iterables) { + checkNotNull(iterable); + } + } + + /** + * Returns an empty iterator if the argument is null, + * or {@code iterable.iterator()} otherwise. + * + * @param the element type + * @param iterable the iterable, possibly null + * @return an empty iterator if the argument is null + */ + private static Iterator emptyIteratorIfNull(final Iterable iterable) { + return iterable != null ? iterable.iterator() : IteratorUtils.emptyIterator(); + } + +} diff --git a/src/org/apache/commons/collections4/IteratorUtils.java b/src/org/apache/commons/collections4/IteratorUtils.java new file mode 100644 index 0000000..8ae5dec --- /dev/null +++ b/src/org/apache/commons/collections4/IteratorUtils.java @@ -0,0 +1,1531 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import org.apache.commons.collections4.functors.EqualPredicate; +import org.apache.commons.collections4.iterators.ArrayIterator; +import org.apache.commons.collections4.iterators.ArrayListIterator; +import org.apache.commons.collections4.iterators.BoundedIterator; +import org.apache.commons.collections4.iterators.CollatingIterator; +import org.apache.commons.collections4.iterators.EmptyIterator; +import org.apache.commons.collections4.iterators.EmptyListIterator; +import org.apache.commons.collections4.iterators.EmptyMapIterator; +import org.apache.commons.collections4.iterators.EmptyOrderedIterator; +import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator; +import org.apache.commons.collections4.iterators.EnumerationIterator; +import org.apache.commons.collections4.iterators.FilterIterator; +import org.apache.commons.collections4.iterators.FilterListIterator; +import org.apache.commons.collections4.iterators.IteratorChain; +import org.apache.commons.collections4.iterators.IteratorEnumeration; +import org.apache.commons.collections4.iterators.IteratorIterable; +import org.apache.commons.collections4.iterators.ListIteratorWrapper; +import org.apache.commons.collections4.iterators.LoopingIterator; +import org.apache.commons.collections4.iterators.LoopingListIterator; +import org.apache.commons.collections4.iterators.NodeListIterator; +import org.apache.commons.collections4.iterators.ObjectArrayIterator; +import org.apache.commons.collections4.iterators.ObjectArrayListIterator; +import org.apache.commons.collections4.iterators.ObjectGraphIterator; +import org.apache.commons.collections4.iterators.PeekingIterator; +import org.apache.commons.collections4.iterators.PushbackIterator; +import org.apache.commons.collections4.iterators.SingletonIterator; +import org.apache.commons.collections4.iterators.SingletonListIterator; +import org.apache.commons.collections4.iterators.SkippingIterator; +import org.apache.commons.collections4.iterators.TransformIterator; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; +import org.apache.commons.collections4.iterators.UnmodifiableListIterator; +import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; +import org.apache.commons.collections4.iterators.ZippingIterator; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Provides static utility methods and decorators for {@link Iterator} + * instances. The implementations are provided in the iterators subpackage. + * + * @since 2.1 + * @version $Id: IteratorUtils.java 1715973 2015-11-23 21:42:01Z tn $ + */ +public class IteratorUtils { + // validation is done in this class in certain cases because the + // public classes allow invalid states + + /** + * An iterator over no elements. + */ + @SuppressWarnings("rawtypes") + public static final ResettableIterator EMPTY_ITERATOR = EmptyIterator.RESETTABLE_INSTANCE; + + /** + * A list iterator over no elements. + */ + @SuppressWarnings("rawtypes") + public static final ResettableListIterator EMPTY_LIST_ITERATOR = EmptyListIterator.RESETTABLE_INSTANCE; + + /** + * An ordered iterator over no elements. + */ + @SuppressWarnings("rawtypes") + public static final OrderedIterator EMPTY_ORDERED_ITERATOR = EmptyOrderedIterator.INSTANCE; + + /** + * A map iterator over no elements. + */ + @SuppressWarnings("rawtypes") + public static final MapIterator EMPTY_MAP_ITERATOR = EmptyMapIterator.INSTANCE; + + /** + * An ordered map iterator over no elements. + */ + @SuppressWarnings("rawtypes") + public static final OrderedMapIterator EMPTY_ORDERED_MAP_ITERATOR = EmptyOrderedMapIterator.INSTANCE; + + /** + * Default prefix used while converting an Iterator to its String representation. + */ + private static final String DEFAULT_TOSTRING_PREFIX = "["; + + /** + * Default suffix used while converting an Iterator to its String representation. + */ + private static final String DEFAULT_TOSTRING_SUFFIX = "]"; + + /** + * Default delimiter used to delimit elements while converting an Iterator + * to its String representation. + */ + private static final String DEFAULT_TOSTRING_DELIMITER = ", "; + + /** + * IteratorUtils is not normally instantiated. + */ + private IteratorUtils() {} + + // Empty + //----------------------------------------------------------------------- + /** + * Gets an empty iterator. + *

      + * This iterator is a valid iterator object that will iterate over nothing. + * + * @param the element type + * @return an iterator over nothing + */ + public static ResettableIterator emptyIterator() { + return EmptyIterator.resettableEmptyIterator(); + } + + /** + * Gets an empty list iterator. + *

      + * This iterator is a valid list iterator object that will iterate + * over nothing. + * + * @param the element type + * @return a list iterator over nothing + */ + public static ResettableListIterator emptyListIterator() { + return EmptyListIterator.resettableEmptyListIterator(); + } + + /** + * Gets an empty ordered iterator. + *

      + * This iterator is a valid iterator object that will iterate + * over nothing. + * + * @param the element type + * @return an ordered iterator over nothing + */ + public static OrderedIterator emptyOrderedIterator() { + return EmptyOrderedIterator.emptyOrderedIterator(); + } + + /** + * Gets an empty map iterator. + *

      + * This iterator is a valid map iterator object that will iterate + * over nothing. + * + * @param the key type + * @param the value type + * @return a map iterator over nothing + */ + public static MapIterator emptyMapIterator() { + return EmptyMapIterator.emptyMapIterator(); + } + + /** + * Gets an empty ordered map iterator. + *

      + * This iterator is a valid map iterator object that will iterate + * over nothing. + * + * @param the key type + * @param the value type + * @return a map iterator over nothing + */ + public static OrderedMapIterator emptyOrderedMapIterator() { + return EmptyOrderedMapIterator.emptyOrderedMapIterator(); + } + + // Singleton + //----------------------------------------------------------------------- + /** + * Gets a singleton iterator. + *

      + * This iterator is a valid iterator object that will iterate over + * the specified object. + * + * @param the element type + * @param object the single object over which to iterate + * @return a singleton iterator over the object + */ + public static ResettableIterator singletonIterator(final E object) { + return new SingletonIterator(object); + } + + /** + * Gets a singleton list iterator. + *

      + * This iterator is a valid list iterator object that will iterate over + * the specified object. + * + * @param the element type + * @param object the single object over which to iterate + * @return a singleton list iterator over the object + */ + public static ListIterator singletonListIterator(final E object) { + return new SingletonListIterator(object); + } + + // Arrays + //----------------------------------------------------------------------- + /** + * Gets an iterator over an object array. + * + * @param the element type + * @param array the array over which to iterate + * @return an iterator over the array + * @throws NullPointerException if array is null + */ + @SafeVarargs + public static ResettableIterator arrayIterator(final E... array) { + return new ObjectArrayIterator(array); + } + + /** + * Gets an iterator over an object or primitive array. + *

      + * This method will handle primitive arrays as well as object arrays. + * The primitives will be wrapped in the appropriate wrapper class. + * + * @param the element type + * @param array the array over which to iterate + * @return an iterator over the array + * @throws IllegalArgumentException if the array is not an array + * @throws NullPointerException if array is null + */ + public static ResettableIterator arrayIterator(final Object array) { + return new ArrayIterator(array); + } + + /** + * Gets an iterator over the end part of an object array. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @return an iterator over part of the array + * @throws IndexOutOfBoundsException if start is less than zero or greater + * than the length of the array + * @throws NullPointerException if array is null + */ + public static ResettableIterator arrayIterator(final E[] array, final int start) { + return new ObjectArrayIterator(array, start); + } + + /** + * Gets an iterator over the end part of an object or primitive array. + *

      + * This method will handle primitive arrays as well as object arrays. + * The primitives will be wrapped in the appropriate wrapper class. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @return an iterator over part of the array + * @throws IllegalArgumentException if the array is not an array + * @throws IndexOutOfBoundsException if start is less than zero or greater + * than the length of the array + * @throws NullPointerException if array is null + */ + public static ResettableIterator arrayIterator(final Object array, final int start) { + return new ArrayIterator(array, start); + } + + /** + * Gets an iterator over part of an object array. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @param end the index to finish iterating at + * @return an iterator over part of the array + * @throws IndexOutOfBoundsException if array bounds are invalid + * @throws IllegalArgumentException if end is before start + * @throws NullPointerException if array is null + */ + public static ResettableIterator arrayIterator(final E[] array, final int start, final int end) { + return new ObjectArrayIterator(array, start, end); + } + + /** + * Gets an iterator over part of an object or primitive array. + *

      + * This method will handle primitive arrays as well as object arrays. + * The primitives will be wrapped in the appropriate wrapper class. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @param end the index to finish iterating at + * @return an iterator over part of the array + * @throws IllegalArgumentException if the array is not an array or end is before start + * @throws IndexOutOfBoundsException if array bounds are invalid + * @throws NullPointerException if array is null + */ + public static ResettableIterator arrayIterator(final Object array, final int start, final int end) { + return new ArrayIterator(array, start, end); + } + + //----------------------------------------------------------------------- + /** + * Gets a list iterator over an object array. + * + * @param the element type + * @param array the array over which to iterate + * @return a list iterator over the array + * @throws NullPointerException if array is null + */ + @SafeVarargs + public static ResettableListIterator arrayListIterator(final E... array) { + return new ObjectArrayListIterator(array); + } + + /** + * Gets a list iterator over an object or primitive array. + *

      + * This method will handle primitive arrays as well as object arrays. + * The primitives will be wrapped in the appropriate wrapper class. + * + * @param the element type + * @param array the array over which to iterate + * @return a list iterator over the array + * @throws IllegalArgumentException if the array is not an array + * @throws NullPointerException if array is null + */ + public static ResettableListIterator arrayListIterator(final Object array) { + return new ArrayListIterator(array); + } + + /** + * Gets a list iterator over the end part of an object array. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @return a list iterator over part of the array + * @throws IndexOutOfBoundsException if start is less than zero + * @throws NullPointerException if array is null + */ + public static ResettableListIterator arrayListIterator(final E[] array, final int start) { + return new ObjectArrayListIterator(array, start); + } + + /** + * Gets a list iterator over the end part of an object or primitive array. + *

      + * This method will handle primitive arrays as well as object arrays. + * The primitives will be wrapped in the appropriate wrapper class. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @return a list iterator over part of the array + * @throws IllegalArgumentException if the array is not an array + * @throws IndexOutOfBoundsException if start is less than zero + * @throws NullPointerException if array is null + */ + public static ResettableListIterator arrayListIterator(final Object array, final int start) { + return new ArrayListIterator(array, start); + } + + /** + * Gets a list iterator over part of an object array. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @param end the index to finish iterating at + * @return a list iterator over part of the array + * @throws IndexOutOfBoundsException if array bounds are invalid + * @throws IllegalArgumentException if end is before start + * @throws NullPointerException if array is null + */ + public static ResettableListIterator arrayListIterator(final E[] array, final int start, final int end) { + return new ObjectArrayListIterator(array, start, end); + } + + /** + * Gets a list iterator over part of an object or primitive array. + *

      + * This method will handle primitive arrays as well as object arrays. + * The primitives will be wrapped in the appropriate wrapper class. + * + * @param the element type + * @param array the array over which to iterate + * @param start the index to start iterating at + * @param end the index to finish iterating at + * @return a list iterator over part of the array + * @throws IllegalArgumentException if the array is not an array or end is before start + * @throws IndexOutOfBoundsException if array bounds are invalid + * @throws NullPointerException if array is null + */ + public static ResettableListIterator arrayListIterator(final Object array, final int start, final int end) { + return new ArrayListIterator(array, start, end); + } + + // Bounded + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator to return at most the given number + * of elements. + * + * @param the element type + * @param iterator the iterator to decorate + * @param max the maximum number of elements returned by this iterator + * @return a new bounded iterator + * @throws NullPointerException if the iterator is null + * @throws IllegalArgumentException if max is negative + * @since 4.1 + */ + public static BoundedIterator boundedIterator(final Iterator iterator, long max) { + return boundedIterator(iterator, 0, max); + } + + /** + * Decorates the specified iterator to return at most the given number + * of elements, skipping all elements until the iterator reaches the + * position at {@code offset}. + *

      + * The iterator is immediately advanced until it reaches the position at + * {@code offset}, incurring O(n) time. + * + * @param the element type + * @param iterator the iterator to decorate + * @param offset the index of the first element of the decorated iterator to return + * @param max the maximum number of elements returned by this iterator + * @return a new bounded iterator + * @throws NullPointerException if the iterator is null + * @throws IllegalArgumentException if either offset or max is negative + * @since 4.1 + */ + public static BoundedIterator boundedIterator(final Iterator iterator, + long offset, long max) { + return new BoundedIterator(iterator, offset, max); + } + + // Unmodifiable + //----------------------------------------------------------------------- + /** + * Gets an immutable version of an {@link Iterator}. The returned object + * will always throw an {@link UnsupportedOperationException} for + * the {@link Iterator#remove} method. + * + * @param the element type + * @param iterator the iterator to make immutable + * @return an immutable version of the iterator + */ + public static Iterator unmodifiableIterator(final Iterator iterator) { + return UnmodifiableIterator.unmodifiableIterator(iterator); + } + + /** + * Gets an immutable version of a {@link ListIterator}. The returned object + * will always throw an {@link UnsupportedOperationException} for + * the {@link Iterator#remove}, {@link ListIterator#add} and + * {@link ListIterator#set} methods. + * + * @param the element type + * @param listIterator the iterator to make immutable + * @return an immutable version of the iterator + */ + public static ListIterator unmodifiableListIterator(final ListIterator listIterator) { + return UnmodifiableListIterator.umodifiableListIterator(listIterator); + } + + /** + * Gets an immutable version of a {@link MapIterator}. The returned object + * will always throw an {@link UnsupportedOperationException} for + * the {@link Iterator#remove}, {@link MapIterator#setValue(Object)} methods. + * + * @param the key type + * @param the value type + * @param mapIterator the iterator to make immutable + * @return an immutable version of the iterator + */ + public static MapIterator unmodifiableMapIterator(final MapIterator mapIterator) { + return UnmodifiableMapIterator.unmodifiableMapIterator(mapIterator); + } + + // Chained + //----------------------------------------------------------------------- + + /** + * Gets an iterator that iterates through two {@link Iterator}s + * one after another. + * + * @param the element type + * @param iterator1 the first iterator to use, not null + * @param iterator2 the second iterator to use, not null + * @return a combination iterator over the iterators + * @throws NullPointerException if either iterator is null + */ + public static Iterator chainedIterator(final Iterator iterator1, + final Iterator iterator2) { + // keep a version with two iterators to avoid the following warning in client code (Java 5 & 6) + // "A generic array of E is created for a varargs parameter" + return new IteratorChain(iterator1, iterator2); + } + + /** + * Gets an iterator that iterates through an array of {@link Iterator}s + * one after another. + * + * @param the element type + * @param iterators the iterators to use, not null or empty or contain nulls + * @return a combination iterator over the iterators + * @throws NullPointerException if iterators array is null or contains a null + */ + @SafeVarargs + public static Iterator chainedIterator(final Iterator... iterators) { + return new IteratorChain(iterators); + } + + /** + * Gets an iterator that iterates through a collections of {@link Iterator}s + * one after another. + * + * @param the element type + * @param iterators the iterators to use, not null or empty or contain nulls + * @return a combination iterator over the iterators + * @throws NullPointerException if iterators collection is null or contains a null + * @throws ClassCastException if the iterators collection contains the wrong object type + */ + public static Iterator chainedIterator(final Collection> iterators) { + return new IteratorChain(iterators); + } + + // Collated + //----------------------------------------------------------------------- + /** + * Gets an iterator that provides an ordered iteration over the elements + * contained in a collection of ordered {@link Iterator}s. + *

      + * Given two ordered {@link Iterator}s A and B, + * the {@link Iterator#next()} method will return the lesser of + * A.next() and B.next(). + *

      + * The comparator is optional. If null is specified then natural order is used. + * + * @param the element type + * @param comparator the comparator to use, may be null for natural order + * @param iterator1 the first iterators to use, not null + * @param iterator2 the first iterators to use, not null + * @return a combination iterator over the iterators + * @throws NullPointerException if either iterator is null + */ + public static Iterator collatedIterator(final Comparator comparator, + final Iterator iterator1, + final Iterator iterator2) { + @SuppressWarnings("unchecked") + final Comparator comp = + comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : (Comparator) comparator; + return new CollatingIterator(comp, iterator1, iterator2); + } + + /** + * Gets an iterator that provides an ordered iteration over the elements + * contained in an array of {@link Iterator}s. + *

      + * Given two ordered {@link Iterator}s A and B, + * the {@link Iterator#next()} method will return the lesser of + * A.next() and B.next() and so on. + *

      + * The comparator is optional. If null is specified then natural order is used. + * + * @param the element type + * @param comparator the comparator to use, may be null for natural order + * @param iterators the iterators to use, not null or empty or contain nulls + * @return a combination iterator over the iterators + * @throws NullPointerException if iterators array is null or contains a null value + */ + @SafeVarargs + public static Iterator collatedIterator(final Comparator comparator, + final Iterator... iterators) { + @SuppressWarnings("unchecked") + final Comparator comp = + comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : (Comparator) comparator; + return new CollatingIterator(comp, iterators); + } + + /** + * Gets an iterator that provides an ordered iteration over the elements + * contained in a collection of {@link Iterator}s. + *

      + * Given two ordered {@link Iterator}s A and B, + * the {@link Iterator#next()} method will return the lesser of + * A.next() and B.next() and so on. + *

      + * The comparator is optional. If null is specified then natural order is used. + * + * @param the element type + * @param comparator the comparator to use, may be null for natural order + * @param iterators the iterators to use, not null or empty or contain nulls + * @return a combination iterator over the iterators + * @throws NullPointerException if iterators collection is null or contains a null + * @throws ClassCastException if the iterators collection contains the wrong object type + */ + public static Iterator collatedIterator(final Comparator comparator, + final Collection> iterators) { + @SuppressWarnings("unchecked") + final Comparator comp = + comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : (Comparator) comparator; + return new CollatingIterator(comp, iterators); + } + + // Object Graph + //----------------------------------------------------------------------- + /** + * Gets an iterator that operates over an object graph. + *

      + * This iterator can extract multiple objects from a complex tree-like object graph. + * The iteration starts from a single root object. + * It uses a Transformer to extract the iterators and elements. + * Its main benefit is that no intermediate List is created. + *

      + * For example, consider an object graph: + *

      +     *                 |- Branch -- Leaf
      +     *                 |         \- Leaf
      +     *         |- Tree |         /- Leaf
      +     *         |       |- Branch -- Leaf
      +     *  Forest |                 \- Leaf
      +     *         |       |- Branch -- Leaf
      +     *         |       |         \- Leaf
      +     *         |- Tree |         /- Leaf
      +     *                 |- Branch -- Leaf
      +     *                 |- Branch -- Leaf
      + * The following Transformer, used in this class, will extract all + * the Leaf objects without creating a combined intermediate list: + *
      +     * public Object transform(Object input) {
      +     *   if (input instanceof Forest) {
      +     *     return ((Forest) input).treeIterator();
      +     *   }
      +     *   if (input instanceof Tree) {
      +     *     return ((Tree) input).branchIterator();
      +     *   }
      +     *   if (input instanceof Branch) {
      +     *     return ((Branch) input).leafIterator();
      +     *   }
      +     *   if (input instanceof Leaf) {
      +     *     return input;
      +     *   }
      +     *   throw new ClassCastException();
      +     * }
      + *

      + * Internally, iteration starts from the root object. When next is called, + * the transformer is called to examine the object. The transformer will return + * either an iterator or an object. If the object is an Iterator, the next element + * from that iterator is obtained and the process repeats. If the element is an object + * it is returned. + *

      + * Under many circumstances, linking Iterators together in this manner is + * more efficient (and convenient) than using nested for loops to extract a list. + * + * @param the element type + * @param root the root object to start iterating from, null results in an empty iterator + * @param transformer the transformer to use, see above, null uses no effect transformer + * @return a new object graph iterator + * @since 3.1 + */ + public static Iterator objectGraphIterator(final E root, + final Transformer transformer) { + return new ObjectGraphIterator(root, transformer); + } + + // Transformed + //----------------------------------------------------------------------- + /** + * Gets an iterator that transforms the elements of another iterator. + *

      + * The transformation occurs during the next() method and the underlying + * iterator is unaffected by the transformation. + * + * @param the input type + * @param the output type + * @param iterator the iterator to use, not null + * @param transform the transform to use, not null + * @return a new transforming iterator + * @throws NullPointerException if either parameter is null + */ + public static Iterator transformedIterator(final Iterator iterator, + final Transformer transform) { + + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (transform == null) { + throw new NullPointerException("Transformer must not be null"); + } + return new TransformIterator(iterator, transform); + } + + // Filtered + //----------------------------------------------------------------------- + /** + * Gets an iterator that filters another iterator. + *

      + * The returned iterator will only return objects that match the specified + * filtering predicate. + * + * @param the element type + * @param iterator the iterator to use, not null + * @param predicate the predicate to use as a filter, not null + * @return a new filtered iterator + * @throws NullPointerException if either parameter is null + */ + public static Iterator filteredIterator(final Iterator iterator, + final Predicate predicate) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new FilterIterator(iterator, predicate); + } + + /** + * Gets a list iterator that filters another list iterator. + *

      + * The returned iterator will only return objects that match the specified + * filtering predicate. + * + * @param the element type + * @param listIterator the list iterator to use, not null + * @param predicate the predicate to use as a filter, not null + * @return a new filtered iterator + * @throws NullPointerException if either parameter is null + */ + public static ListIterator filteredListIterator(final ListIterator listIterator, + final Predicate predicate) { + + if (listIterator == null) { + throw new NullPointerException("ListIterator must not be null"); + } + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new FilterListIterator(listIterator, predicate); + } + + // Looping + //----------------------------------------------------------------------- + /** + * Gets an iterator that loops continuously over the supplied collection. + *

      + * The iterator will only stop looping if the remove method is called + * enough times to empty the collection, or if the collection is empty + * to start with. + * + * @param the element type + * @param coll the collection to iterate over, not null + * @return a new looping iterator + * @throws NullPointerException if the collection is null + */ + public static ResettableIterator loopingIterator(final Collection coll) { + if (coll == null) { + throw new NullPointerException("Collection must not be null"); + } + return new LoopingIterator(coll); + } + + /** + * Gets an iterator that loops continuously over the supplied list. + *

      + * The iterator will only stop looping if the remove method is called + * enough times to empty the list, or if the list is empty to start with. + * + * @param the element type + * @param list the list to iterate over, not null + * @return a new looping iterator + * @throws NullPointerException if the list is null + * @since 3.2 + */ + public static ResettableListIterator loopingListIterator(final List list) { + if (list == null) { + throw new NullPointerException("List must not be null"); + } + return new LoopingListIterator(list); + } + + // org.w3c.dom.NodeList iterators + //----------------------------------------------------------------------- + /** + * Gets an {@link Iterator} that wraps the specified {@link NodeList}. + * The returned {@link Iterator} can be used for a single iteration. + * + * @param nodeList the node list to use, may not be null + * @return a new, single use {@link Iterator} + * @throws NullPointerException if nodeList is null + * @since 4.0 + */ + public static NodeListIterator nodeListIterator(final NodeList nodeList) { + if (nodeList == null) { + throw new NullPointerException("NodeList must not be null"); + } + return new NodeListIterator(nodeList); + } + + /** + * Gets an {@link Iterator} that wraps the specified node's childNodes. + * The returned {@link Iterator} can be used for a single iteration. + *

      + * Convenience method, allows easy iteration over NodeLists: + *

      +     *   Iterator<Node> iterator = IteratorUtils.nodeListIterator(node);
      +     *   for(Node childNode : IteratorUtils.asIterable(iterator)) {
      +     *     ...
      +     *   }
      +     * 
      + * + * @param node the node to use, may not be null + * @return a new, single use {@link Iterator} + * @throws NullPointerException if node is null + * @since 4.0 + */ + public static NodeListIterator nodeListIterator(final Node node) { + if (node == null) { + throw new NullPointerException("Node must not be null"); + } + return new NodeListIterator(node); + } + + // Peeking + //----------------------------------------------------------------------- + + /** + * Gets an iterator that supports one-element lookahead. + * + * @param the element type + * @param iterator the iterator to decorate, not null + * @return a peeking iterator + * @throws NullPointerException if the iterator is null + * @since 4.0 + */ + public static Iterator peekingIterator(final Iterator iterator) { + return PeekingIterator.peekingIterator(iterator); + } + + // Pushback + //----------------------------------------------------------------------- + + /** + * Gets an iterator that supports pushback of elements. + * + * @param the element type + * @param iterator the iterator to decorate, not null + * @return a pushback iterator + * @throws NullPointerException if the iterator is null + * @since 4.0 + */ + public static Iterator pushbackIterator(final Iterator iterator) { + return PushbackIterator.pushbackIterator(iterator); + } + + // Skipping + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator to skip the first N elements. + * + * @param the element type + * @param iterator the iterator to decorate + * @param offset the first number of elements to skip + * @return a new skipping iterator + * @throws NullPointerException if the iterator is null + * @throws IllegalArgumentException if offset is negative + * @since 4.1 + */ + public static SkippingIterator skippingIterator(final Iterator iterator, long offset) { + return new SkippingIterator(iterator, offset); + } + + // Zipping + //----------------------------------------------------------------------- + /** + * Returns an iterator that interleaves elements from the decorated iterators. + * + * @param the element type + * @param a the first iterator to interleave + * @param b the second iterator to interleave + * @return an iterator, interleaving the decorated iterators + * @throws NullPointerException if any iterator is null + * @since 4.1 + */ + public static ZippingIterator zippingIterator(final Iterator a, + final Iterator b) { + return new ZippingIterator(a, b); + } + + /** + * Returns an iterator that interleaves elements from the decorated iterators. + * + * @param the element type + * @param a the first iterator to interleave + * @param b the second iterator to interleave + * @param c the third iterator to interleave + * @return an iterator, interleaving the decorated iterators + * @throws NullPointerException if any iterator is null + * @since 4.1 + */ + public static ZippingIterator zippingIterator(final Iterator a, + final Iterator b, + final Iterator c) { + return new ZippingIterator(a, b, c); + } + + /** + * Returns an iterator that interleaves elements from the decorated iterators. + * + * @param the element type + * @param iterators the array of iterators to interleave + * @return an iterator, interleaving the decorated iterators + * @throws NullPointerException if any iterator is null + * @since 4.1 + */ + @SafeVarargs + public static ZippingIterator zippingIterator(final Iterator... iterators) { + return new ZippingIterator(iterators); + } + + // Views + //----------------------------------------------------------------------- + /** + * Gets an iterator that provides an iterator view of the given enumeration. + * + * @param the element type + * @param enumeration the enumeration to use, may not be null + * @return a new iterator + * @throws NullPointerException if enumeration is null + */ + public static Iterator asIterator(final Enumeration enumeration) { + if (enumeration == null) { + throw new NullPointerException("Enumeration must not be null"); + } + return new EnumerationIterator(enumeration); + } + + /** + * Gets an iterator that provides an iterator view of the given enumeration + * that will remove elements from the specified collection. + * + * @param the element type + * @param enumeration the enumeration to use, may not be null + * @param removeCollection the collection to remove elements from, may not be null + * @return a new iterator + * @throws NullPointerException if enumeration or removeCollection is null + */ + public static Iterator asIterator(final Enumeration enumeration, + final Collection removeCollection) { + if (enumeration == null) { + throw new NullPointerException("Enumeration must not be null"); + } + if (removeCollection == null) { + throw new NullPointerException("Collection must not be null"); + } + return new EnumerationIterator(enumeration, removeCollection); + } + + /** + * Gets an enumeration that wraps an iterator. + * + * @param the element type + * @param iterator the iterator to use, may not be null + * @return a new enumeration + * @throws NullPointerException if iterator is null + */ + public static Enumeration asEnumeration(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + return new IteratorEnumeration(iterator); + } + + /** + * Gets an {@link Iterable} that wraps an iterator. The returned {@link Iterable} can be + * used for a single iteration. + * + * @param the element type + * @param iterator the iterator to use, may not be null + * @return a new, single use {@link Iterable} + * @throws NullPointerException if iterator is null + */ + public static Iterable asIterable(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + return new IteratorIterable(iterator, false); + } + + /** + * Gets an iterable that wraps an iterator. The returned iterable can be + * used for multiple iterations. + * + * @param the element type + * @param iterator the iterator to use, may not be null + * @return a new, multiple use iterable + * @throws NullPointerException if iterator is null + */ + public static Iterable asMultipleUseIterable(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + return new IteratorIterable(iterator, true); + } + + /** + * Gets a list iterator based on a simple iterator. + *

      + * As the wrapped Iterator is traversed, a LinkedList of its values is + * cached, permitting all required operations of ListIterator. + * + * @param the element type + * @param iterator the iterator to use, may not be null + * @return a new iterator + * @throws NullPointerException if iterator parameter is null + */ + public static ListIterator toListIterator(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + return new ListIteratorWrapper(iterator); + } + + /** + * Gets an array based on an iterator. + *

      + * As the wrapped Iterator is traversed, an ArrayList of its values is + * created. At the end, this is converted to an array. + * + * @param iterator the iterator to use, not null + * @return an array of the iterator contents + * @throws NullPointerException if iterator parameter is null + */ + public static Object[] toArray(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + final List list = toList(iterator, 100); + return list.toArray(); + } + + /** + * Gets an array based on an iterator. + *

      + * As the wrapped Iterator is traversed, an ArrayList of its values is + * created. At the end, this is converted to an array. + * + * @param the element type + * @param iterator the iterator to use, not null + * @param arrayClass the class of array to create + * @return an array of the iterator contents + * @throws NullPointerException if iterator parameter or arrayClass is null + * @throws ArrayStoreException if the arrayClass is invalid + */ + public static E[] toArray(final Iterator iterator, final Class arrayClass) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (arrayClass == null) { + throw new NullPointerException("Array class must not be null"); + } + final List list = toList(iterator, 100); + @SuppressWarnings("unchecked") + final E[] array = (E[]) Array.newInstance(arrayClass, list.size()); + return list.toArray(array); + } + + /** + * Gets a list based on an iterator. + *

      + * As the wrapped Iterator is traversed, an ArrayList of its values is + * created. At the end, the list is returned. + * + * @param the element type + * @param iterator the iterator to use, not null + * @return a list of the iterator contents + * @throws NullPointerException if iterator parameter is null + */ + public static List toList(final Iterator iterator) { + return toList(iterator, 10); + } + + /** + * Gets a list based on an iterator. + *

      + * As the wrapped Iterator is traversed, an ArrayList of its values is + * created. At the end, the list is returned. + * + * @param the element type + * @param iterator the iterator to use, not null + * @param estimatedSize the initial size of the ArrayList + * @return a list of the iterator contents + * @throws NullPointerException if iterator parameter is null + * @throws IllegalArgumentException if the size is less than 1 + */ + public static List toList(final Iterator iterator, final int estimatedSize) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (estimatedSize < 1) { + throw new IllegalArgumentException("Estimated size must be greater than 0"); + } + final List list = new ArrayList(estimatedSize); + while (iterator.hasNext()) { + list.add(iterator.next()); + } + return list; + } + + /** + * Gets a suitable Iterator for the given object. + *

      + * This method can handle objects as follows + *

        + *
      • null - empty iterator + *
      • Iterator - returned directly + *
      • Enumeration - wrapped + *
      • Collection - iterator from collection returned + *
      • Map - values iterator returned + *
      • Dictionary - values (elements) enumeration returned as iterator + *
      • array - iterator over array returned + *
      • object with iterator() public method accessed by reflection + *
      • object - singleton iterator + *
      • NodeList - iterator over the list + *
      • Node - iterator over the child nodes + *
      + * + * @param obj the object to convert to an iterator + * @return a suitable iterator, never null + */ + public static Iterator getIterator(final Object obj) { + if (obj == null) { + return emptyIterator(); + } + if (obj instanceof Iterator) { + return (Iterator) obj; + } + if (obj instanceof Iterable) { + return ((Iterable) obj).iterator(); + } + if (obj instanceof Object[]) { + return new ObjectArrayIterator((Object[]) obj); + } + if (obj instanceof Enumeration) { + return new EnumerationIterator((Enumeration) obj); + } + if (obj instanceof Map) { + return ((Map) obj).values().iterator(); + } + if (obj instanceof NodeList) { + return new NodeListIterator((NodeList) obj); + } + if (obj instanceof Node) { + return new NodeListIterator((Node) obj); + } + if (obj instanceof Dictionary) { + return new EnumerationIterator(((Dictionary) obj).elements()); + } else if (obj.getClass().isArray()) { + return new ArrayIterator(obj); + } + try { + final Method method = obj.getClass().getMethod("iterator", (Class[]) null); + if (Iterator.class.isAssignableFrom(method.getReturnType())) { + final Iterator it = (Iterator) method.invoke(obj, (Object[]) null); + if (it != null) { + return it; + } + } + } catch (final RuntimeException e) { // NOPMD + // ignore + } catch (final NoSuchMethodException e) { // NOPMD + // ignore + } catch (final IllegalAccessException e) { // NOPMD + // ignore + } catch (final InvocationTargetException e) { // NOPMD + // ignore + } + return singletonIterator(obj); + } + + // Utility methods + //----------------------------------------------------------------------- + + /** + * Applies the closure to each element of the provided iterator. + * + * @param the element type + * @param iterator the iterator to use, may be null + * @param closure the closure to apply to each element, may not be null + * @throws NullPointerException if closure is null + * @since 4.1 + */ + public static void forEach(final Iterator iterator, final Closure closure) { + if (closure == null) { + throw new NullPointerException("Closure must not be null"); + } + + if (iterator != null) { + while (iterator.hasNext()) { + final E element = iterator.next(); + closure.execute(element); + } + } + } + + /** + * Executes the given closure on each but the last element in the iterator. + *

      + * If the input iterator is null no change is made. + * + * @param the type of object the {@link Iterator} contains + * @param iterator the iterator to get the input from, may be null + * @param closure the closure to perform, may not be null + * @return the last element in the iterator, or null if iterator is null or empty + * @throws NullPointerException if closure is null + * @since 4.1 + */ + public static E forEachButLast(final Iterator iterator, final Closure closure) { + if (closure == null) { + throw new NullPointerException("Closure must not be null."); + } + if (iterator != null) { + while (iterator.hasNext()) { + final E element = iterator.next(); + if (iterator.hasNext()) { + closure.execute(element); + } else { + return element; + } + } + } + return null; + } + + /** + * Finds the first element in the given iterator which matches the given predicate. + *

      + * A null or empty iterator returns null. + * + * @param the element type + * @param iterator the iterator to search, may be null + * @param predicate the predicate to use, may not be null + * @return the first element of the iterator which matches the predicate or null if none could be found + * @throws NullPointerException if predicate is null + * @since 4.1 + */ + public static E find(final Iterator iterator, final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + + if (iterator != null) { + while (iterator.hasNext()) { + final E element = iterator.next(); + if (predicate.evaluate(element)) { + return element; + } + } + } + return null; + } + + /** + * Returns the index of the first element in the specified iterator that + * matches the given predicate. + *

      + * A null or empty iterator returns -1. + * + * @param the element type + * @param iterator the iterator to search, may be null + * @param predicate the predicate to use, may not be null + * @return the index of the first element which matches the predicate or -1 if none matches + * @throws NullPointerException if predicate is null + * @since 4.1 + */ + public static int indexOf(final Iterator iterator, final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + + if (iterator != null) { + for(int index = 0; iterator.hasNext(); index++) { + final E element = iterator.next(); + if (predicate.evaluate(element)) { + return index; + } + } + } + return -1; + } + + /** + * Answers true if a predicate is true for any element of the iterator. + *

      + * A null or empty iterator returns false. + * + * @param the type of object the {@link Iterator} contains + * @param iterator the {@link Iterator} to use, may be null + * @param predicate the predicate to use, may not be null + * @return true if any element of the collection matches the predicate, false otherwise + * @throws NullPointerException if predicate is null + * @since 4.1 + */ + public static boolean matchesAny(final Iterator iterator, final Predicate predicate) { + return indexOf(iterator, predicate) != -1; + } + + /** + * Answers true if a predicate is true for every element of an iterator. + *

      + * A null or empty iterator returns true. + * + * @param the type of object the {@link Iterator} contains + * @param iterator the {@link Iterator} to use, may be null + * @param predicate the predicate to use, may not be null + * @return true if every element of the collection matches the predicate or if the + * collection is empty, false otherwise + * @throws NullPointerException if predicate is null + * @since 4.1 + */ + public static boolean matchesAll(final Iterator iterator, final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + + if (iterator != null) { + while (iterator.hasNext()) { + final E element = iterator.next(); + if (!predicate.evaluate(element)) { + return false; + } + } + } + return true; + } + + /** + * Checks if the given iterator is empty. + *

      + * A null or empty iterator returns true. + * + * @param iterator the {@link Iterator} to use, may be null + * @return true if the iterator is exhausted or null, false otherwise + * @since 4.1 + */ + public static boolean isEmpty(final Iterator iterator) { + return iterator == null || !iterator.hasNext(); + } + + /** + * Checks if the object is contained in the given iterator. + *

      + * A null or empty iterator returns false. + * + * @param the type of object the {@link Iterator} contains + * @param iterator the iterator to check, may be null + * @param object the object to check + * @return true if the object is contained in the iterator, false otherwise + * @since 4.1 + */ + public static boolean contains(final Iterator iterator, final Object object) { + return matchesAny(iterator, EqualPredicate.equalPredicate(object)); + } + + /** + * Returns the index-th value in {@link Iterator}, throwing + * IndexOutOfBoundsException if there is no such element. + *

      + * The Iterator is advanced to index (or to the end, if + * index exceeds the number of entries) as a side effect of this method. + * + * @param the type of object in the {@link Iterator} + * @param iterator the iterator to get a value from + * @param index the index to get + * @return the object at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + * @since 4.1 + */ + public static E get(final Iterator iterator, final int index) { + int i = index; + CollectionUtils.checkIndexBounds(i); + while (iterator.hasNext()) { + i--; + if (i == -1) { + return iterator.next(); + } + iterator.next(); + } + throw new IndexOutOfBoundsException("Entry does not exist: " + i); + } + + /** + * Returns the number of elements contained in the given iterator. + *

      + * A null or empty iterator returns {@code 0}. + * + * @param iterator the iterator to check, may be null + * @return the number of elements contained in the iterator + * @since 4.1 + */ + public static int size(final Iterator iterator) { + int size = 0; + if (iterator != null) { + while (iterator.hasNext()) { + iterator.next(); + size++; + } + } + return size; + } + + /** + * Returns a string representation of the elements of the specified iterator. + *

      + * The string representation consists of a list of the iterator's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated + * by the characters {@code ", "} (a comma followed by a space). Elements are + * converted to strings as by {@code String.valueOf(Object)}. + * + * @param the element type + * @param iterator the iterator to convert to a string, may be null + * @return a string representation of {@code iterator} + * @since 4.1 + */ + public static String toString(final Iterator iterator) { + return toString(iterator, TransformerUtils.stringValueTransformer(), + DEFAULT_TOSTRING_DELIMITER, DEFAULT_TOSTRING_PREFIX, + DEFAULT_TOSTRING_SUFFIX); + } + + /** + * Returns a string representation of the elements of the specified iterator. + *

      + * The string representation consists of a list of the iterable's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated + * by the characters {@code ", "} (a comma followed by a space). Elements are + * converted to strings as by using the provided {@code transformer}. + * + * @param the element type + * @param iterator the iterator to convert to a string, may be null + * @param transformer the transformer used to get a string representation of an element + * @return a string representation of {@code iterator} + * @throws NullPointerException if {@code transformer} is null + * @since 4.1 + */ + public static String toString(final Iterator iterator, + final Transformer transformer) { + return toString(iterator, transformer, DEFAULT_TOSTRING_DELIMITER, + DEFAULT_TOSTRING_PREFIX, DEFAULT_TOSTRING_SUFFIX); + } + + /** + * Returns a string representation of the elements of the specified iterator. + *

      + * The string representation consists of a list of the iterator's elements, + * enclosed by the provided {@code prefix} and {@code suffix}. Adjacent elements + * are separated by the provided {@code delimiter}. Elements are converted to + * strings as by using the provided {@code transformer}. + * + * @param the element type + * @param iterator the iterator to convert to a string, may be null + * @param transformer the transformer used to get a string representation of an element + * @param delimiter the string to delimit elements + * @param prefix the prefix, prepended to the string representation + * @param suffix the suffix, appended to the string representation + * @return a string representation of {@code iterator} + * @throws NullPointerException if either transformer, delimiter, prefix or suffix is null + * @since 4.1 + */ + public static String toString(final Iterator iterator, + final Transformer transformer, + final String delimiter, + final String prefix, + final String suffix) { + if (transformer == null) { + throw new NullPointerException("transformer may not be null"); + } + if (delimiter == null) { + throw new NullPointerException("delimiter may not be null"); + } + if (prefix == null) { + throw new NullPointerException("prefix may not be null"); + } + if (suffix == null) { + throw new NullPointerException("suffix may not be null"); + } + final StringBuilder stringBuilder = new StringBuilder(prefix); + if (iterator != null) { + while (iterator.hasNext()) { + final E element = iterator.next(); + stringBuilder.append(transformer.transform(element)); + stringBuilder.append(delimiter); + } + if(stringBuilder.length() > prefix.length()) { + stringBuilder.setLength(stringBuilder.length() - delimiter.length()); + } + } + stringBuilder.append(suffix); + return stringBuilder.toString(); + } + +} diff --git a/src/org/apache/commons/collections4/KeyValue.java b/src/org/apache/commons/collections4/KeyValue.java new file mode 100644 index 0000000..81d0a11 --- /dev/null +++ b/src/org/apache/commons/collections4/KeyValue.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a simple key value pair. + *

      + * A Map Entry has considerable additional semantics over and above a simple + * key-value pair. This interface defines the minimum key value, with just the + * two get methods. + * + * @param the type of the key + * @param the type of the value + * @since 3.0 + * @version $Id: KeyValue.java 1477779 2013-04-30 18:55:24Z tn $ + */ +public interface KeyValue { + + /** + * Gets the key from the pair. + * + * @return the key + */ + K getKey(); + + /** + * Gets the value from the pair. + * + * @return the value + */ + V getValue(); + +} diff --git a/src/org/apache/commons/collections4/ListUtils.java b/src/org/apache/commons/collections4/ListUtils.java new file mode 100644 index 0000000..d9a6be9 --- /dev/null +++ b/src/org/apache/commons/collections4/ListUtils.java @@ -0,0 +1,699 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.collections4.bag.HashBag; +import org.apache.commons.collections4.functors.DefaultEquator; +import org.apache.commons.collections4.list.FixedSizeList; +import org.apache.commons.collections4.list.LazyList; +import org.apache.commons.collections4.list.PredicatedList; +import org.apache.commons.collections4.list.TransformedList; +import org.apache.commons.collections4.list.UnmodifiableList; +import org.apache.commons.collections4.sequence.CommandVisitor; +import org.apache.commons.collections4.sequence.EditScript; +import org.apache.commons.collections4.sequence.SequencesComparator; + +/** + * Provides utility methods and decorators for {@link List} instances. + * + * @since 1.0 + * @version $Id: ListUtils.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ListUtils { + + /** + * ListUtils should not normally be instantiated. + */ + private ListUtils() {} + + //----------------------------------------------------------------------- + + /** + * Returns an immutable empty list if the argument is null, + * or the argument itself otherwise. + * + * @param the element type + * @param list the list, possibly null + * @return an empty list if the argument is null + */ + public static List emptyIfNull(final List list) { + return list == null ? Collections.emptyList() : list; + } + + /** + * Returns either the passed in list, or if the list is {@code null}, + * the value of {@code defaultList}. + * + * @param the element type + * @param list the list, possibly {@code null} + * @param defaultList the returned values if list is {@code null} + * @return an empty list if the argument is null + * @since 4.0 + */ + public static List defaultIfNull(final List list, final List defaultList) { + return list == null ? defaultList : list; + } + + /** + * Returns a new list containing all elements that are contained in + * both given lists. + * + * @param the element type + * @param list1 the first list + * @param list2 the second list + * @return the intersection of those two lists + * @throws NullPointerException if either list is null + */ + public static List intersection(final List list1, final List list2) { + final List result = new ArrayList(); + + List smaller = list1; + List larger = list2; + if (list1.size() > list2.size()) { + smaller = list2; + larger = list1; + } + + final HashSet hashSet = new HashSet(smaller); + + for (final E e : larger) { + if (hashSet.contains(e)) { + result.add(e); + hashSet.remove(e); + } + } + return result; + } + + /** + * Subtracts all elements in the second list from the first list, + * placing the results in a new list. + *

      + * This differs from {@link List#removeAll(Collection)} in that + * cardinality is respected; if list1 contains two + * occurrences of null and list2 only + * contains one occurrence, then the returned list will still contain + * one occurrence. + * + * @param the element type + * @param list1 the list to subtract from + * @param list2 the list to subtract + * @return a new list containing the results + * @throws NullPointerException if either list is null + */ + public static List subtract(final List list1, final List list2) { + final ArrayList result = new ArrayList(); + final HashBag bag = new HashBag(list2); + for (final E e : list1) { + if (!bag.remove(e, 1)) { + result.add(e); + } + } + return result; + } + + /** + * Returns the sum of the given lists. This is their intersection + * subtracted from their union. + * + * @param the element type + * @param list1 the first list + * @param list2 the second list + * @return a new list containing the sum of those lists + * @throws NullPointerException if either list is null + */ + public static List sum(final List list1, final List list2) { + return subtract(union(list1, list2), intersection(list1, list2)); + } + + /** + * Returns a new list containing the second list appended to the + * first list. The {@link List#addAll(Collection)} operation is + * used to append the two given lists into a new list. + * + * @param the element type + * @param list1 the first list + * @param list2 the second list + * @return a new list containing the union of those lists + * @throws NullPointerException if either list is null + */ + public static List union(final List list1, final List list2) { + final ArrayList result = new ArrayList(list1); + result.addAll(list2); + return result; + } + + /** + * Selects all elements from input collection which match the given + * predicate into an output list. + *

      + * A null predicate matches no elements. + * + * @param the element type + * @param inputCollection the collection to get the input from, may not be null + * @param predicate the predicate to use, may be null + * @return the elements matching the predicate (new list) + * @throws NullPointerException if the input list is null + * + * @since 4.0 + * @see CollectionUtils#select(Iterable, Predicate) + */ + public static List select(final Collection inputCollection, + final Predicate predicate) { + return CollectionUtils.select(inputCollection, predicate, new ArrayList(inputCollection.size())); + } + + /** + * Selects all elements from inputCollection which don't match the given + * predicate into an output collection. + *

      + * If the input predicate is null, the result is an empty list. + * + * @param the element type + * @param inputCollection the collection to get the input from, may not be null + * @param predicate the predicate to use, may be null + * @return the elements not matching the predicate (new list) + * @throws NullPointerException if the input collection is null + * + * @since 4.0 + * @see CollectionUtils#selectRejected(Iterable, Predicate) + */ + public static List selectRejected(final Collection inputCollection, + final Predicate predicate) { + return CollectionUtils.selectRejected(inputCollection, predicate, new ArrayList(inputCollection.size())); + } + + /** + * Tests two lists for value-equality as per the equality contract in + * {@link java.util.List#equals(java.lang.Object)}. + *

      + * This method is useful for implementing List when you cannot + * extend AbstractList. The method takes Collection instances to enable other + * collection types to use the List implementation algorithm. + *

      + * The relevant text (slightly paraphrased as this is a static method) is: + *

      + * Compares the two list objects for equality. Returns + * {@code true} if and only if both + * lists have the same size, and all corresponding pairs of elements in + * the two lists are equal. (Two elements {@code e1} and + * {@code e2} are equal if (e1==null ? e2==null : + * e1.equals(e2)).) In other words, two lists are defined to be + * equal if they contain the same elements in the same order. This + * definition ensures that the equals method works properly across + * different implementations of the {@code List} interface. + *
      + * + * Note: The behaviour of this method is undefined if the lists are + * modified during the equals comparison. + * + * @see java.util.List + * @param list1 the first list, may be null + * @param list2 the second list, may be null + * @return whether the lists are equal by value comparison + */ + public static boolean isEqualList(final Collection list1, final Collection list2) { + if (list1 == list2) { + return true; + } + if (list1 == null || list2 == null || list1.size() != list2.size()) { + return false; + } + + final Iterator it1 = list1.iterator(); + final Iterator it2 = list2.iterator(); + Object obj1 = null; + Object obj2 = null; + + while (it1.hasNext() && it2.hasNext()) { + obj1 = it1.next(); + obj2 = it2.next(); + + if (!(obj1 == null ? obj2 == null : obj1.equals(obj2))) { + return false; + } + } + + return !(it1.hasNext() || it2.hasNext()); + } + + /** + * Generates a hash code using the algorithm specified in + * {@link java.util.List#hashCode()}. + *

      + * This method is useful for implementing List when you cannot + * extend AbstractList. The method takes Collection instances to enable other + * collection types to use the List implementation algorithm. + * + * @see java.util.List#hashCode() + * @param list the list to generate the hashCode for, may be null + * @return the hash code + */ + public static int hashCodeForList(final Collection list) { + if (list == null) { + return 0; + } + int hashCode = 1; + final Iterator it = list.iterator(); + + while (it.hasNext()) { + final Object obj = it.next(); + hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); + } + return hashCode; + } + + //----------------------------------------------------------------------- + /** + * Returns a List containing all the elements in collection + * that are also in retain. The cardinality of an element e + * in the returned list is the same as the cardinality of e + * in collection unless retain does not contain e, in which + * case the cardinality is zero. This method is useful if you do not wish to modify + * the collection c and thus cannot call collection.retainAll(retain);. + *

      + * This implementation iterates over collection, checking each element in + * turn to see if it's contained in retain. If it's contained, it's added + * to the returned list. As a consequence, it is advised to use a collection type for + * retain that provides a fast (e.g. O(1)) implementation of + * {@link Collection#contains(Object)}. + * + * @param the element type + * @param collection the collection whose contents are the target of the #retailAll operation + * @param retain the collection containing the elements to be retained in the returned collection + * @return a List containing all the elements of c + * that occur at least once in retain. + * @throws NullPointerException if either parameter is null + * @since 3.2 + */ + public static List retainAll(final Collection collection, final Collection retain) { + final List list = new ArrayList(Math.min(collection.size(), retain.size())); + + for (final E obj : collection) { + if (retain.contains(obj)) { + list.add(obj); + } + } + return list; + } + + /** + * Removes the elements in remove from collection. That is, this + * method returns a list containing all the elements in collection + * that are not in remove. The cardinality of an element e + * in the returned collection is the same as the cardinality of e + * in collection unless remove contains e, in which + * case the cardinality is zero. This method is useful if you do not wish to modify + * collection and thus cannot call collection.removeAll(remove);. + *

      + * This implementation iterates over collection, checking each element in + * turn to see if it's contained in remove. If it's not contained, it's added + * to the returned list. As a consequence, it is advised to use a collection type for + * remove that provides a fast (e.g. O(1)) implementation of + * {@link Collection#contains(Object)}. + * + * @param the element type + * @param collection the collection from which items are removed (in the returned collection) + * @param remove the items to be removed from the returned collection + * @return a List containing all the elements of c except + * any elements that also occur in remove. + * @throws NullPointerException if either parameter is null + * @since 3.2 + */ + public static List removeAll(final Collection collection, final Collection remove) { + final List list = new ArrayList(); + for (final E obj : collection) { + if (!remove.contains(obj)) { + list.add(obj); + } + } + return list; + } + + //----------------------------------------------------------------------- + /** + * Returns a synchronized list backed by the given list. + *

      + * You must manually synchronize on the returned list's iterator to + * avoid non-deterministic behavior: + * + *

      +     * List list = ListUtils.synchronizedList(myList);
      +     * synchronized (list) {
      +     *     Iterator i = list.iterator();
      +     *     while (i.hasNext()) {
      +     *         process (i.next());
      +     *     }
      +     * }
      +     * 
      + * + * This method is just a wrapper for {@link Collections#synchronizedList(List)}. + * + * @param the element type + * @param list the list to synchronize, must not be null + * @return a synchronized list backed by the given list + * @throws NullPointerException if the list is null + */ + public static List synchronizedList(final List list) { + return Collections.synchronizedList(list); + } + + /** + * Returns an unmodifiable list backed by the given list. + *

      + * This method uses the implementation in the decorators subpackage. + * + * @param the element type + * @param list the list to make unmodifiable, must not be null + * @return an unmodifiable list backed by the given list + * @throws NullPointerException if the list is null + */ + public static List unmodifiableList(final List list) { + return UnmodifiableList.unmodifiableList(list); + } + + /** + * Returns a predicated (validating) list backed by the given list. + *

      + * Only objects that pass the test in the given predicate can be added to the list. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original list after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the element type + * @param list the list to predicate, must not be null + * @param predicate the predicate for the list, must not be null + * @return a predicated list backed by the given list + * @throws NullPointerException if the List or Predicate is null + */ + public static List predicatedList(final List list, final Predicate predicate) { + return PredicatedList.predicatedList(list, predicate); + } + + /** + * Returns a transformed list backed by the given list. + *

      + * This method returns a new list (decorating the specified list) that + * will transform any new entries added to it. + * Existing entries in the specified list will not be transformed. + *

      + * Each object is passed through the transformer as it is added to the + * List. It is important not to use the original list after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

      + * Existing entries in the specified list will not be transformed. + * If you want that behaviour, see {@link TransformedList#transformedList}. + * + * @param the element type + * @param list the list to predicate, must not be null + * @param transformer the transformer for the list, must not be null + * @return a transformed list backed by the given list + * @throws NullPointerException if the List or Transformer is null + */ + public static List transformedList(final List list, + final Transformer transformer) { + return TransformedList.transformingList(list, transformer); + } + + /** + * Returns a "lazy" list whose elements will be created on demand. + *

      + * When the index passed to the returned list's {@link List#get(int) get} + * method is greater than the list's size, then the factory will be used + * to create a new object and that object will be inserted at that index. + *

      + * For instance: + * + *

      +     * Factory<Date> factory = new Factory<Date>() {
      +     *     public Date create() {
      +     *         return new Date();
      +     *     }
      +     * }
      +     * List<Date> lazy = ListUtils.lazyList(new ArrayList<Date>(), factory);
      +     * Date date = lazy.get(3);
      +     * 
      + * + * After the above code is executed, date will refer to + * a new Date instance. Furthermore, that Date + * instance is the fourth element in the list. The first, second, + * and third element are all set to null. + * + * @param the element type + * @param list the list to make lazy, must not be null + * @param factory the factory for creating new objects, must not be null + * @return a lazy list backed by the given list + * @throws NullPointerException if the List or Factory is null + */ + public static List lazyList(final List list, final Factory factory) { + return LazyList.lazyList(list, factory); + } + + /** + * Returns a fixed-sized list backed by the given list. + * Elements may not be added or removed from the returned list, but + * existing elements can be changed (for instance, via the + * {@link List#set(int, Object)} method). + * + * @param the element type + * @param list the list whose size to fix, must not be null + * @return a fixed-size list backed by that list + * @throws NullPointerException if the List is null + */ + public static List fixedSizeList(final List list) { + return FixedSizeList.fixedSizeList(list); + } + + //----------------------------------------------------------------------- + /** + * Finds the first index in the given List which matches the given predicate. + *

      + * If the input List or predicate is null, or no element of the List + * matches the predicate, -1 is returned. + * + * @param the element type + * @param list the List to search, may be null + * @param predicate the predicate to use, may be null + * @return the first index of an Object in the List which matches the predicate or -1 if none could be found + */ + public static int indexOf(final List list, final Predicate predicate) { + if (list != null && predicate != null) { + for (int i = 0; i < list.size(); i++) { + final E item = list.get(i); + if (predicate.evaluate(item)) { + return i; + } + } + } + return -1; + } + + //----------------------------------------------------------------------- + /** + * Returns the longest common subsequence (LCS) of two sequences (lists). + * + * @param the element type + * @param a the first list + * @param b the second list + * @return the longest common subsequence + * @throws NullPointerException if either list is {@code null} + * @since 4.0 + */ + public static List longestCommonSubsequence(final List a, final List b) { + return longestCommonSubsequence( a, b, DefaultEquator.defaultEquator() ); + } + + /** + * Returns the longest common subsequence (LCS) of two sequences (lists). + * + * @param the element type + * @param a the first list + * @param b the second list + * @param equator the equator used to test object equality + * @return the longest common subsequence + * @throws NullPointerException if either list or the equator is {@code null} + * @since 4.0 + */ + public static List longestCommonSubsequence(final List a, final List b, + final Equator equator) { + if (a == null || b == null) { + throw new NullPointerException("List must not be null"); + } + if (equator == null) { + throw new NullPointerException("Equator must not be null"); + } + + final SequencesComparator comparator = new SequencesComparator(a, b, equator); + final EditScript script = comparator.getScript(); + final LcsVisitor visitor = new LcsVisitor(); + script.visit(visitor); + return visitor.getSubSequence(); + } + + /** + * Returns the longest common subsequence (LCS) of two {@link CharSequence} objects. + *

      + * This is a convenience method for using {@link #longestCommonSubsequence(List, List)} + * with {@link CharSequence} instances. + * + * @param a the first sequence + * @param b the second sequence + * @return the longest common subsequence as {@link String} + * @throws NullPointerException if either sequence is {@code null} + * @since 4.0 + */ + public static String longestCommonSubsequence(final CharSequence a, final CharSequence b) { + if (a == null || b == null) { + throw new NullPointerException("CharSequence must not be null"); + } + final List lcs = longestCommonSubsequence(new CharSequenceAsList( a ), new CharSequenceAsList( b )); + final StringBuilder sb = new StringBuilder(); + for ( Character ch : lcs ) { + sb.append(ch); + } + return sb.toString(); + } + + /** + * A helper class used to construct the longest common subsequence. + */ + private static final class LcsVisitor implements CommandVisitor { + private ArrayList sequence; + + public LcsVisitor() { + sequence = new ArrayList(); + } + + public void visitInsertCommand(final E object) {} + + public void visitDeleteCommand(final E object) {} + + public void visitKeepCommand(final E object) { + sequence.add(object); + } + + public List getSubSequence() { + return sequence; + } + } + + /** + * A simple wrapper to use a CharSequence as List. + */ + private static final class CharSequenceAsList extends AbstractList { + + private final CharSequence sequence; + + public CharSequenceAsList(final CharSequence sequence) { + this.sequence = sequence; + } + + @Override + public Character get( int index ) { + return Character.valueOf(sequence.charAt( index )); + } + + @Override + public int size() { + return sequence.length(); + } + + } + + //----------------------------------------------------------------------- + /** + * Returns consecutive {@link List#subList(int, int) sublists} of a + * list, each of the same size (the final list may be smaller). For example, + * partitioning a list containing {@code [a, b, c, d, e]} with a partition + * size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing + * two inner lists of three and two elements, all in the original order. + *

      + * The outer list is unmodifiable, but reflects the latest state of the + * source list. The inner lists are sublist views of the original list, + * produced on demand using {@link List#subList(int, int)}, and are subject + * to all the usual caveats about modification as explained in that API. + *

      + * Adapted from http://code.google.com/p/guava-libraries/ + * + * @param the element type + * @param list the list to return consecutive sublists of + * @param size the desired size of each sublist (the last may be smaller) + * @return a list of consecutive sublists + * @throws NullPointerException if list is null + * @throws IllegalArgumentException if size is not strictly positive + * @since 4.0 + */ + public static List> partition(final List list, final int size) { + if (list == null) { + throw new NullPointerException("List must not be null"); + } + if (size <= 0) { + throw new IllegalArgumentException("Size must be greater than 0"); + } + return new Partition(list, size); + } + + /** + * Provides a partition view on a {@link List}. + * @since 4.0 + */ + private static class Partition extends AbstractList> { + private final List list; + private final int size; + + private Partition(final List list, final int size) { + this.list = list; + this.size = size; + } + + @Override + public List get(final int index) { + final int listSize = size(); + if (listSize < 0) { + throw new IllegalArgumentException("negative size: " + listSize); + } + if (index < 0) { + throw new IndexOutOfBoundsException("Index " + index + " must not be negative"); + } + if (index >= listSize) { + throw new IndexOutOfBoundsException("Index " + index + " must be less than size " + + listSize); + } + final int start = index * size; + final int end = Math.min(start + size, list.size()); + return list.subList(start, end); + } + + @Override + public int size() { + return (list.size() + size - 1) / size; + } + + @Override + public boolean isEmpty() { + return list.isEmpty(); + } + } +} diff --git a/src/org/apache/commons/collections4/ListValuedMap.java b/src/org/apache/commons/collections4/ListValuedMap.java new file mode 100644 index 0000000..0f8d6ef --- /dev/null +++ b/src/org/apache/commons/collections4/ListValuedMap.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.List; + +/** + * Defines a map that holds a list of values against each key. + *

      + * A {@code ListValuedMap} is a Map with slightly different semantics: + *

        + *
      • Putting a value into the map will add the value to a {@link List} at that key.
      • + *
      • Getting a value will return a {@link List}, holding all the values put to that key.
      • + *
      + * + * @since 4.1 + * @version $Id: ListValuedMap.java 1685299 2015-06-13 18:27:11Z tn $ + */ +public interface ListValuedMap extends MultiValuedMap { + + /** + * Gets the list of values associated with the specified key. + *

      + * This method will return an empty list if + * {@link #containsKey(Object)} returns {@code false}. Changes to the + * returned list will update the underlying {@code ListValuedMap} and + * vice-versa. + * + * @param key the key to retrieve + * @return the {@code List} of values, implementations should return an + * empty {@code List} for no mapping + * @throws NullPointerException if the key is null and null keys are invalid + */ + @Override + List get(K key); + + /** + * Removes all values associated with the specified key. + *

      + * The returned list may be modifiable, but updates will not be + * propagated to this list-valued map. In case no mapping was stored for the + * specified key, an empty, unmodifiable list will be returned. + * + * @param key the key to remove values from + * @return the {@code List} of values removed, implementations + * typically return an empty, unmodifiable {@code List} for no mapping found + * @throws UnsupportedOperationException if the map is unmodifiable + * @throws NullPointerException if the key is null and null keys are invalid + */ + @Override + List remove(Object key); + +} diff --git a/src/org/apache/commons/collections4/MapIterator.java b/src/org/apache/commons/collections4/MapIterator.java new file mode 100644 index 0000000..fc9a9a6 --- /dev/null +++ b/src/org/apache/commons/collections4/MapIterator.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Iterator; + +/** + * Defines an iterator that operates over a Map. + *

      + * This iterator is a special version designed for maps. It can be more + * efficient to use this rather than an entry set iterator where the option + * is available, and it is certainly more convenient. + *

      + * A map that provides this interface may not hold the data internally using + * Map Entry objects, thus this interface can avoid lots of object creation. + *

      + * In use, this iterator iterates through the keys in the map. After each call + * to next(), the getValue() method provides direct + * access to the value. The value can also be set using setValue(). + *

      + * MapIterator it = map.mapIterator();
      + * while (it.hasNext()) {
      + *   String key = it.next();
      + *   Integer value = it.getValue();
      + *   it.setValue(value + 1);
      + * }
      + * 
      + * + * @param the type of the keys in the map + * @param the type of the values in the map + * @since 3.0 + * @version $Id: MapIterator.java 1469004 2013-04-17 17:37:03Z tn $ + */ +public interface MapIterator extends Iterator { + + /** + * Checks to see if there are more entries still to be iterated. + * + * @return true if the iterator has more elements + */ + boolean hasNext(); + + /** + * Gets the next key from the Map. + * + * @return the next key in the iteration + * @throws java.util.NoSuchElementException if the iteration is finished + */ + K next(); + + //----------------------------------------------------------------------- + /** + * Gets the current key, which is the key returned by the last call + * to next(). + * + * @return the current key + * @throws IllegalStateException if next() has not yet been called + */ + K getKey(); + + /** + * Gets the current value, which is the value associated with the last key + * returned by next(). + * + * @return the current value + * @throws IllegalStateException if next() has not yet been called + */ + V getValue(); + + //----------------------------------------------------------------------- + /** + * Removes the last returned key from the underlying Map (optional operation). + *

      + * This method can be called once per call to next(). + * + * @throws UnsupportedOperationException if remove is not supported by the map + * @throws IllegalStateException if next() has not yet been called + * @throws IllegalStateException if remove() has already been called + * since the last call to next() + */ + void remove(); + + /** + * Sets the value associated with the current key (optional operation). + * + * @param value the new value + * @return the previous value + * @throws UnsupportedOperationException if setValue is not supported by the map + * @throws IllegalStateException if next() has not yet been called + * @throws IllegalStateException if remove() has been called since the + * last call to next() + */ + V setValue(V value); + +} diff --git a/src/org/apache/commons/collections4/MapUtils.java b/src/org/apache/commons/collections4/MapUtils.java new file mode 100644 index 0000000..34aa4a0 --- /dev/null +++ b/src/org/apache/commons/collections4/MapUtils.java @@ -0,0 +1,1798 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.io.PrintStream; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections4.map.AbstractMapDecorator; +import org.apache.commons.collections4.map.AbstractSortedMapDecorator; +import org.apache.commons.collections4.map.FixedSizeMap; +import org.apache.commons.collections4.map.FixedSizeSortedMap; +import org.apache.commons.collections4.map.LazyMap; +import org.apache.commons.collections4.map.LazySortedMap; +import org.apache.commons.collections4.map.ListOrderedMap; +import org.apache.commons.collections4.map.MultiValueMap; +import org.apache.commons.collections4.map.PredicatedMap; +import org.apache.commons.collections4.map.PredicatedSortedMap; +import org.apache.commons.collections4.map.TransformedMap; +import org.apache.commons.collections4.map.TransformedSortedMap; +import org.apache.commons.collections4.map.UnmodifiableMap; +import org.apache.commons.collections4.map.UnmodifiableSortedMap; + +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * Provides utility methods and decorators for + * {@link Map} and {@link SortedMap} instances. + *

      + * It contains various type safe methods + * as well as other useful features like deep copying. + *

      + * It also provides the following decorators: + * + *

        + *
      • {@link #fixedSizeMap(Map)} + *
      • {@link #fixedSizeSortedMap(SortedMap)} + *
      • {@link #lazyMap(Map,Factory)} + *
      • {@link #lazyMap(Map,Transformer)} + *
      • {@link #lazySortedMap(SortedMap,Factory)} + *
      • {@link #lazySortedMap(SortedMap,Transformer)} + *
      • {@link #predicatedMap(Map,Predicate,Predicate)} + *
      • {@link #predicatedSortedMap(SortedMap,Predicate,Predicate)} + *
      • {@link #transformedMap(Map, Transformer, Transformer)} + *
      • {@link #transformedSortedMap(SortedMap, Transformer, Transformer)} + *
      • {@link #multiValueMap( Map )} + *
      • {@link #multiValueMap( Map, Class )} + *
      • {@link #multiValueMap( Map, Factory )} + *
      + * + * @since 1.0 + * @version $Id: MapUtils.java 1686921 2015-06-22 19:48:47Z tn $ + */ +@SuppressWarnings("deprecation") +public class MapUtils { + + /** + * An empty unmodifiable sorted map. + * This is not provided in the JDK. + */ + @SuppressWarnings("rawtypes") + public static final SortedMap EMPTY_SORTED_MAP = + UnmodifiableSortedMap.unmodifiableSortedMap(new TreeMap()); + + /** + * String used to indent the verbose and debug Map prints. + */ + private static final String INDENT_STRING = " "; + + /** + * MapUtils should not normally be instantiated. + */ + private MapUtils() {} + + // Type safe getters + //------------------------------------------------------------------------- + /** + * Gets from a Map in a null-safe manner. + * + * @param the key type + * @param the value type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map, null if null map input + */ + public static V getObject(final Map map, final K key) { + if (map != null) { + return map.get(key); + } + return null; + } + + /** + * Gets a String from a Map in a null-safe manner. + *

      + * The String is obtained via toString. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a String, null if null map input + */ + public static String getString(final Map map, final K key) { + if (map != null) { + final Object answer = map.get(key); + if (answer != null) { + return answer.toString(); + } + } + return null; + } + + /** + * Gets a Boolean from a Map in a null-safe manner. + *

      + * If the value is a Boolean it is returned directly. + * If the value is a String and it equals 'true' ignoring case + * then true is returned, otherwise false. + * If the value is a Number an integer zero value returns + * false and non-zero returns true. + * Otherwise, null is returned. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Boolean, null if null map input + */ + public static Boolean getBoolean(final Map map, final K key) { + if (map != null) { + final Object answer = map.get(key); + if (answer != null) { + if (answer instanceof Boolean) { + return (Boolean) answer; + } + if (answer instanceof String) { + return Boolean.valueOf((String) answer); + } + if (answer instanceof Number) { + final Number n = (Number) answer; + return n.intValue() != 0 ? Boolean.TRUE : Boolean.FALSE; + } + } + } + return null; + } + + /** + * Gets a Number from a Map in a null-safe manner. + *

      + * If the value is a Number it is returned directly. + * If the value is a String it is converted using + * {@link NumberFormat#parse(String)} on the system default formatter + * returning null if the conversion fails. + * Otherwise, null is returned. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Number, null if null map input + */ + public static Number getNumber(final Map map, final K key) { + if (map != null) { + final Object answer = map.get(key); + if (answer != null) { + if (answer instanceof Number) { + return (Number) answer; + } + if (answer instanceof String) { + try { + final String text = (String) answer; + return NumberFormat.getInstance().parse(text); + } catch (final ParseException e) { // NOPMD + // failure means null is returned + } + } + } + } + return null; + } + + /** + * Gets a Byte from a Map in a null-safe manner. + *

      + * The Byte is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Byte, null if null map input + */ + public static Byte getByte(final Map map, final K key) { + final Number answer = getNumber(map, key); + if (answer == null) { + return null; + } + if (answer instanceof Byte) { + return (Byte) answer; + } + return Byte.valueOf(answer.byteValue()); + } + + /** + * Gets a Short from a Map in a null-safe manner. + *

      + * The Short is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Short, null if null map input + */ + public static Short getShort(final Map map, final K key) { + final Number answer = getNumber(map, key); + if (answer == null) { + return null; + } + if (answer instanceof Short) { + return (Short) answer; + } + return Short.valueOf(answer.shortValue()); + } + + /** + * Gets a Integer from a Map in a null-safe manner. + *

      + * The Integer is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Integer, null if null map input + */ + public static Integer getInteger(final Map map, final K key) { + final Number answer = getNumber(map, key); + if (answer == null) { + return null; + } + if (answer instanceof Integer) { + return (Integer) answer; + } + return Integer.valueOf(answer.intValue()); + } + + /** + * Gets a Long from a Map in a null-safe manner. + *

      + * The Long is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Long, null if null map input + */ + public static Long getLong(final Map map, final K key) { + final Number answer = getNumber(map, key); + if (answer == null) { + return null; + } + if (answer instanceof Long) { + return (Long) answer; + } + return Long.valueOf(answer.longValue()); + } + + /** + * Gets a Float from a Map in a null-safe manner. + *

      + * The Float is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Float, null if null map input + */ + public static Float getFloat(final Map map, final K key) { + final Number answer = getNumber(map, key); + if (answer == null) { + return null; + } + if (answer instanceof Float) { + return (Float) answer; + } + return Float.valueOf(answer.floatValue()); + } + + /** + * Gets a Double from a Map in a null-safe manner. + *

      + * The Double is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Double, null if null map input + */ + public static Double getDouble(final Map map, final K key) { + final Number answer = getNumber(map, key); + if (answer == null) { + return null; + } + if (answer instanceof Double) { + return (Double) answer; + } + return Double.valueOf(answer.doubleValue()); + } + + /** + * Gets a Map from a Map in a null-safe manner. + *

      + * If the value returned from the specified map is not a Map then + * null is returned. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Map, null if null map input + */ + public static Map getMap(final Map map, final K key) { + if (map != null) { + final Object answer = map.get(key); + if (answer != null && answer instanceof Map) { + return (Map) answer; + } + } + return null; + } + + // Type safe getters with default values + //------------------------------------------------------------------------- + /** + * Looks up the given key in the given map, converting null into the + * given default value. + * + * @param the key type + * @param the value type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null + * @return the value in the map, or defaultValue if the original value + * is null or the map is null + */ + public static V getObject(final Map map, final K key, final V defaultValue) { + if (map != null) { + final V answer = map.get(key); + if (answer != null) { + return answer; + } + } + return defaultValue; + } + + /** + * Looks up the given key in the given map, converting the result into + * a string, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a string, or defaultValue if the + * original value is null, the map is null or the string conversion fails + */ + public static String getString(final Map map, final K key, final String defaultValue) { + String answer = getString(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a boolean, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a boolean, or defaultValue if the + * original value is null, the map is null or the boolean conversion fails + */ + public static Boolean getBoolean(final Map map, final K key, final Boolean defaultValue) { + Boolean answer = getBoolean(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a number, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the number conversion fails + */ + public static Number getNumber(final Map map, final K key, final Number defaultValue) { + Number answer = getNumber(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a byte, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the number conversion fails + */ + public static Byte getByte(final Map map, final K key, final Byte defaultValue) { + Byte answer = getByte(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a short, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the number conversion fails + */ + public static Short getShort(final Map map, final K key, final Short defaultValue) { + Short answer = getShort(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * an integer, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the number conversion fails + */ + public static Integer getInteger(final Map map, final K key, final Integer defaultValue) { + Integer answer = getInteger(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a long, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the number conversion fails + */ + public static Long getLong(final Map map, final K key, final Long defaultValue) { + Long answer = getLong(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a float, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the number conversion fails + */ + public static Float getFloat(final Map map, final K key, final Float defaultValue) { + Float answer = getFloat(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a double, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the number conversion fails + */ + public static Double getDouble(final Map map, final K key, final Double defaultValue) { + Double answer = getDouble(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + /** + * Looks up the given key in the given map, converting the result into + * a map, using the default value if the the conversion fails. + * + * @param the key type + * @param map the map whose value to look up + * @param key the key of the value to look up in that map + * @param defaultValue what to return if the value is null or if the + * conversion fails + * @return the value in the map as a number, or defaultValue if the + * original value is null, the map is null or the map conversion fails + */ + public static Map getMap(final Map map, final K key, final Map defaultValue) { + Map answer = getMap(map, key); + if (answer == null) { + answer = defaultValue; + } + return answer; + } + + // Type safe primitive getters + //------------------------------------------------------------------------- + /** + * Gets a boolean from a Map in a null-safe manner. + *

      + * If the value is a Boolean its value is returned. + * If the value is a String and it equals 'true' ignoring case + * then true is returned, otherwise false. + * If the value is a Number an integer zero value returns + * false and non-zero returns true. + * Otherwise, false is returned. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a Boolean, false if null map input + */ + public static boolean getBooleanValue(final Map map, final K key) { + return Boolean.TRUE.equals(getBoolean(map, key)); + } + + /** + * Gets a byte from a Map in a null-safe manner. + *

      + * The byte is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a byte, 0 if null map input + */ + public static byte getByteValue(final Map map, final K key) { + final Byte byteObject = getByte(map, key); + if (byteObject == null) { + return 0; + } + return byteObject.byteValue(); + } + + /** + * Gets a short from a Map in a null-safe manner. + *

      + * The short is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a short, 0 if null map input + */ + public static short getShortValue(final Map map, final K key) { + final Short shortObject = getShort(map, key); + if (shortObject == null) { + return 0; + } + return shortObject.shortValue(); + } + + /** + * Gets an int from a Map in a null-safe manner. + *

      + * The int is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as an int, 0 if null map input + */ + public static int getIntValue(final Map map, final K key) { + final Integer integerObject = getInteger(map, key); + if (integerObject == null) { + return 0; + } + return integerObject.intValue(); + } + + /** + * Gets a long from a Map in a null-safe manner. + *

      + * The long is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a long, 0L if null map input + */ + public static long getLongValue(final Map map, final K key) { + final Long longObject = getLong(map, key); + if (longObject == null) { + return 0L; + } + return longObject.longValue(); + } + + /** + * Gets a float from a Map in a null-safe manner. + *

      + * The float is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a float, 0.0F if null map input + */ + public static float getFloatValue(final Map map, final K key) { + final Float floatObject = getFloat(map, key); + if (floatObject == null) { + return 0f; + } + return floatObject.floatValue(); + } + + /** + * Gets a double from a Map in a null-safe manner. + *

      + * The double is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @return the value in the Map as a double, 0.0 if null map input + */ + public static double getDoubleValue(final Map map, final K key) { + final Double doubleObject = getDouble(map, key); + if (doubleObject == null) { + return 0d; + } + return doubleObject.doubleValue(); + } + + // Type safe primitive getters with default values + //------------------------------------------------------------------------- + /** + * Gets a boolean from a Map in a null-safe manner, + * using the default value if the the conversion fails. + *

      + * If the value is a Boolean its value is returned. + * If the value is a String and it equals 'true' ignoring case + * then true is returned, otherwise false. + * If the value is a Number an integer zero value returns + * false and non-zero returns true. + * Otherwise, defaultValue is returned. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @param defaultValue return if the value is null or if the conversion fails + * @return the value in the Map as a Boolean, defaultValue if null map input + */ + public static boolean getBooleanValue(final Map map, final K key, final boolean defaultValue) { + final Boolean booleanObject = getBoolean(map, key); + if (booleanObject == null) { + return defaultValue; + } + return booleanObject.booleanValue(); + } + + /** + * Gets a byte from a Map in a null-safe manner, + * using the default value if the the conversion fails. + *

      + * The byte is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @param defaultValue return if the value is null or if the conversion fails + * @return the value in the Map as a byte, defaultValue if null map input + */ + public static byte getByteValue(final Map map, final K key, final byte defaultValue) { + final Byte byteObject = getByte(map, key); + if (byteObject == null) { + return defaultValue; + } + return byteObject.byteValue(); + } + + /** + * Gets a short from a Map in a null-safe manner, + * using the default value if the the conversion fails. + *

      + * The short is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @param defaultValue return if the value is null or if the conversion fails + * @return the value in the Map as a short, defaultValue if null map input + */ + public static short getShortValue(final Map map, final K key, final short defaultValue) { + final Short shortObject = getShort(map, key); + if (shortObject == null) { + return defaultValue; + } + return shortObject.shortValue(); + } + + /** + * Gets an int from a Map in a null-safe manner, + * using the default value if the the conversion fails. + *

      + * The int is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @param defaultValue return if the value is null or if the conversion fails + * @return the value in the Map as an int, defaultValue if null map input + */ + public static int getIntValue(final Map map, final K key, final int defaultValue) { + final Integer integerObject = getInteger(map, key); + if (integerObject == null) { + return defaultValue; + } + return integerObject.intValue(); + } + + /** + * Gets a long from a Map in a null-safe manner, + * using the default value if the the conversion fails. + *

      + * The long is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @param defaultValue return if the value is null or if the conversion fails + * @return the value in the Map as a long, defaultValue if null map input + */ + public static long getLongValue(final Map map, final K key, final long defaultValue) { + final Long longObject = getLong(map, key); + if (longObject == null) { + return defaultValue; + } + return longObject.longValue(); + } + + /** + * Gets a float from a Map in a null-safe manner, + * using the default value if the the conversion fails. + *

      + * The float is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @param defaultValue return if the value is null or if the conversion fails + * @return the value in the Map as a float, defaultValue if null map input + */ + public static float getFloatValue(final Map map, final K key, final float defaultValue) { + final Float floatObject = getFloat(map, key); + if (floatObject == null) { + return defaultValue; + } + return floatObject.floatValue(); + } + + /** + * Gets a double from a Map in a null-safe manner, + * using the default value if the the conversion fails. + *

      + * The double is obtained from the results of {@link #getNumber(Map,Object)}. + * + * @param the key type + * @param map the map to use + * @param key the key to look up + * @param defaultValue return if the value is null or if the conversion fails + * @return the value in the Map as a double, defaultValue if null map input + */ + public static double getDoubleValue(final Map map, final K key, final double defaultValue) { + final Double doubleObject = getDouble(map, key); + if (doubleObject == null) { + return defaultValue; + } + return doubleObject.doubleValue(); + } + + // Conversion methods + //------------------------------------------------------------------------- + /** + * Gets a new Properties object initialised with the values from a Map. + * A null input will return an empty properties object. + *

      + * A Properties object may only store non-null keys and values, thus if + * the provided map contains either a key or value which is {@code null}, + * a {@link NullPointerException} will be thrown. + * + * @param the key type + * @param the value type + * @param map the map to convert to a Properties object + * @return the properties object + * @throws NullPointerException if a key or value in the provided map is {@code null} + */ + public static Properties toProperties(final Map map) { + final Properties answer = new Properties(); + if (map != null) { + for (final Entry entry2 : map.entrySet()) { + final Map.Entry entry = entry2; + final Object key = entry.getKey(); + final Object value = entry.getValue(); + answer.put(key, value); + } + } + return answer; + } + + /** + * Creates a new HashMap using data copied from a ResourceBundle. + * + * @param resourceBundle the resource bundle to convert, may not be null + * @return the hashmap containing the data + * @throws NullPointerException if the bundle is null + */ + public static Map toMap(final ResourceBundle resourceBundle) { + final Enumeration enumeration = resourceBundle.getKeys(); + final Map map = new HashMap(); + + while (enumeration.hasMoreElements()) { + final String key = enumeration.nextElement(); + final Object value = resourceBundle.getObject(key); + map.put(key, value); + } + + return map; + } + + // Printing methods + //------------------------------------------------------------------------- + /** + * Prints the given map with nice line breaks. + *

      + * This method prints a nicely formatted String describing the Map. + * Each map entry will be printed with key and value. + * When the value is a Map, recursive behaviour occurs. + *

      + * This method is NOT thread-safe in any special way. You must manually + * synchronize on either this class or the stream as required. + * + * @param out the stream to print to, must not be null + * @param label The label to be used, may be null. + * If null, the label is not output. + * It typically represents the name of the property in a bean or similar. + * @param map The map to print, may be null. + * If null, the text 'null' is output. + * @throws NullPointerException if the stream is null + */ + public static void verbosePrint(final PrintStream out, final Object label, final Map map) { + verbosePrintInternal(out, label, map, new ArrayDeque>(), false); + } + + /** + * Prints the given map with nice line breaks. + *

      + * This method prints a nicely formatted String describing the Map. + * Each map entry will be printed with key, value and value classname. + * When the value is a Map, recursive behaviour occurs. + *

      + * This method is NOT thread-safe in any special way. You must manually + * synchronize on either this class or the stream as required. + * + * @param out the stream to print to, must not be null + * @param label The label to be used, may be null. + * If null, the label is not output. + * It typically represents the name of the property in a bean or similar. + * @param map The map to print, may be null. + * If null, the text 'null' is output. + * @throws NullPointerException if the stream is null + */ + public static void debugPrint(final PrintStream out, final Object label, final Map map) { + verbosePrintInternal(out, label, map, new ArrayDeque>(), true); + } + + // Implementation methods + //------------------------------------------------------------------------- + /** + * Implementation providing functionality for {@link #debugPrint} and for + * {@link #verbosePrint}. This prints the given map with nice line breaks. + * If the debug flag is true, it additionally prints the type of the object + * value. If the contents of a map include the map itself, then the text + * (this Map) is printed out. If the contents include a + * parent container of the map, the the text (ancestor[i] Map) is + * printed, where i actually indicates the number of levels which must be + * traversed in the sequential list of ancestors (e.g. father, grandfather, + * great-grandfather, etc). + * + * @param out the stream to print to + * @param label the label to be used, may be null. + * If null, the label is not output. + * It typically represents the name of the property in a bean or similar. + * @param map the map to print, may be null. + * If null, the text 'null' is output + * @param lineage a stack consisting of any maps in which the previous + * argument is contained. This is checked to avoid infinite recursion when + * printing the output + * @param debug flag indicating whether type names should be output. + * @throws NullPointerException if the stream is null + */ + private static void verbosePrintInternal(final PrintStream out, final Object label, final Map map, + final Deque> lineage, final boolean debug) { + printIndent(out, lineage.size()); + + if (map == null) { + if (label != null) { + out.print(label); + out.print(" = "); + } + out.println("null"); + return; + } + if (label != null) { + out.print(label); + out.println(" = "); + } + + printIndent(out, lineage.size()); + out.println("{"); + + lineage.addLast(map); + + for (final Map.Entry entry : map.entrySet()) { + final Object childKey = entry.getKey(); + final Object childValue = entry.getValue(); + if (childValue instanceof Map && !lineage.contains(childValue)) { + verbosePrintInternal( + out, + childKey == null ? "null" : childKey, + (Map) childValue, + lineage, + debug); + } else { + printIndent(out, lineage.size()); + out.print(childKey); + out.print(" = "); + + final int lineageIndex = + IterableUtils.indexOf(lineage, + PredicateUtils.equalPredicate(childValue)); + if (lineageIndex == -1) { + out.print(childValue); + } else if (lineage.size() - 1 == lineageIndex) { + out.print("(this Map)"); + } else { + out.print( + "(ancestor[" + + (lineage.size() - 1 - lineageIndex - 1) + + "] Map)"); + } + + if (debug && childValue != null) { + out.print(' '); + out.println(childValue.getClass().getName()); + } else { + out.println(); + } + } + } + + lineage.removeLast(); + + printIndent(out, lineage.size()); + out.println(debug ? "} " + map.getClass().getName() : "}"); + } + + /** + * Writes indentation to the given stream. + * + * @param out the stream to indent + */ + private static void printIndent(final PrintStream out, final int indent) { + for (int i = 0; i < indent; i++) { + out.print(INDENT_STRING); + } + } + + // Misc + //----------------------------------------------------------------------- + /** + * Inverts the supplied map returning a new HashMap such that the keys of + * the input are swapped with the values. + *

      + * This operation assumes that the inverse mapping is well defined. + * If the input map had multiple entries with the same value mapped to + * different keys, the returned map will map one of those keys to the + * value, but the exact key which will be mapped is undefined. + * + * @param the key type + * @param the value type + * @param map the map to invert, may not be null + * @return a new HashMap containing the inverted data + * @throws NullPointerException if the map is null + */ + public static Map invertMap(final Map map) { + final Map out = new HashMap(map.size()); + for (final Entry entry : map.entrySet()) { + out.put(entry.getValue(), entry.getKey()); + } + return out; + } + + //----------------------------------------------------------------------- + /** + * Protects against adding null values to a map. + *

      + * This method checks the value being added to the map, and if it is null + * it is replaced by an empty string. + *

      + * This could be useful if the map does not accept null values, or for + * receiving data from a source that may provide null or empty string + * which should be held in the same way in the map. + *

      + * Keys are not validated. + * Note that this method can be used to circumvent the map's + * value type at runtime. + * + * @param the key type + * @param map the map to add to, may not be null + * @param key the key + * @param value the value, null converted to "" + * @throws NullPointerException if the map is null + */ + public static void safeAddToMap(final Map map, final K key, final Object value) + throws NullPointerException { + map.put(key, value == null ? "" : value); + } + + //----------------------------------------------------------------------- + /** + * Puts all the keys and values from the specified array into the map. + *

      + * This method is an alternative to the {@link java.util.Map#putAll(java.util.Map)} + * method and constructors. It allows you to build a map from an object array + * of various possible styles. + *

      + * If the first entry in the object array implements {@link java.util.Map.Entry} + * or {@link KeyValue} then the key and value are added from that object. + * If the first entry in the object array is an object array itself, then + * it is assumed that index 0 in the sub-array is the key and index 1 is the value. + * Otherwise, the array is treated as keys and values in alternate indices. + *

      + * For example, to create a color map: + *

      +     * Map colorMap = MapUtils.putAll(new HashMap(), new String[][] {
      +     *     {"RED", "#FF0000"},
      +     *     {"GREEN", "#00FF00"},
      +     *     {"BLUE", "#0000FF"}
      +     * });
      +     * 
      + * or: + *
      +     * Map colorMap = MapUtils.putAll(new HashMap(), new String[] {
      +     *     "RED", "#FF0000",
      +     *     "GREEN", "#00FF00",
      +     *     "BLUE", "#0000FF"
      +     * });
      +     * 
      + * or: + *
      +     * Map colorMap = MapUtils.putAll(new HashMap(), new Map.Entry[] {
      +     *     new DefaultMapEntry("RED", "#FF0000"),
      +     *     new DefaultMapEntry("GREEN", "#00FF00"),
      +     *     new DefaultMapEntry("BLUE", "#0000FF")
      +     * });
      +     * 
      + * + * @param the key type + * @param the value type + * @param map the map to populate, must not be null + * @param array an array to populate from, null ignored + * @return the input map + * @throws NullPointerException if map is null + * @throws IllegalArgumentException if sub-array or entry matching used and an entry is invalid + * @throws ClassCastException if the array contents is mixed + * @since 3.2 + */ + @SuppressWarnings("unchecked") // As per Javadoc throws CCE for invalid array contents + public static Map putAll(final Map map, final Object[] array) { + if (map == null) { + throw new NullPointerException("The map must not be null"); + } + if (array == null || array.length == 0) { + return map; + } + final Object obj = array[0]; + if (obj instanceof Map.Entry) { + for (final Object element : array) { + // cast ok here, type is checked above + final Map.Entry entry = (Map.Entry) element; + map.put(entry.getKey(), entry.getValue()); + } + } else if (obj instanceof KeyValue) { + for (final Object element : array) { + // cast ok here, type is checked above + final KeyValue keyval = (KeyValue) element; + map.put(keyval.getKey(), keyval.getValue()); + } + } else if (obj instanceof Object[]) { + for (int i = 0; i < array.length; i++) { + final Object[] sub = (Object[]) array[i]; + if (sub == null || sub.length < 2) { + throw new IllegalArgumentException("Invalid array element: " + i); + } + // these casts can fail if array has incorrect types + map.put((K) sub[0], (V) sub[1]); + } + } else { + for (int i = 0; i < array.length - 1;) { + // these casts can fail if array has incorrect types + map.put((K) array[i++], (V) array[i++]); + } + } + return map; + } + + //----------------------------------------------------------------------- + + /** + * Returns an immutable empty map if the argument is null, + * or the argument itself otherwise. + * + * @param the key type + * @param the value type + * @param map the map, possibly null + * @return an empty map if the argument is null + */ + public static Map emptyIfNull(final Map map) { + return map == null ? Collections.emptyMap() : map; + } + + /** + * Null-safe check if the specified map is empty. + *

      + * Null returns true. + * + * @param map the map to check, may be null + * @return true if empty or null + * @since 3.2 + */ + public static boolean isEmpty(final Map map) { + return map == null || map.isEmpty(); + } + + /** + * Null-safe check if the specified map is not empty. + *

      + * Null returns false. + * + * @param map the map to check, may be null + * @return true if non-null and non-empty + * @since 3.2 + */ + public static boolean isNotEmpty(final Map map) { + return !MapUtils.isEmpty(map); + } + + // Map decorators + //----------------------------------------------------------------------- + /** + * Returns a synchronized map backed by the given map. + *

      + * You must manually synchronize on the returned buffer's iterator to + * avoid non-deterministic behavior: + * + *

      +     * Map m = MapUtils.synchronizedMap(myMap);
      +     * Set s = m.keySet();  // outside synchronized block
      +     * synchronized (m) {  // synchronized on MAP!
      +     *     Iterator i = s.iterator();
      +     *     while (i.hasNext()) {
      +     *         process (i.next());
      +     *     }
      +     * }
      +     * 
      + * + * This method uses the implementation in {@link java.util.Collections Collections}. + * + * @param the key type + * @param the value type + * @param map the map to synchronize, must not be null + * @return a synchronized map backed by the given map + */ + public static Map synchronizedMap(final Map map) { + return Collections.synchronizedMap(map); + } + + /** + * Returns an unmodifiable map backed by the given map. + *

      + * This method uses the implementation in the decorators subpackage. + * + * @param the key type + * @param the value type + * @param map the map to make unmodifiable, must not be null + * @return an unmodifiable map backed by the given map + * @throws NullPointerException if the map is null + */ + public static Map unmodifiableMap(final Map map) { + return UnmodifiableMap.unmodifiableMap(map); + } + + /** + * Returns a predicated (validating) map backed by the given map. + *

      + * Only objects that pass the tests in the given predicates can be added to the map. + * Trying to add an invalid object results in an IllegalArgumentException. + * Keys must pass the key predicate, values must pass the value predicate. + * It is important not to use the original map after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the key type + * @param the value type + * @param map the map to predicate, must not be null + * @param keyPred the predicate for keys, null means no check + * @param valuePred the predicate for values, null means no check + * @return a predicated map backed by the given map + * @throws NullPointerException if the Map is null + */ + public static IterableMap predicatedMap(final Map map, final Predicate keyPred, + final Predicate valuePred) { + return PredicatedMap.predicatedMap(map, keyPred, valuePred); + } + + /** + * Returns a transformed map backed by the given map. + *

      + * This method returns a new map (decorating the specified map) that + * will transform any new entries added to it. + * Existing entries in the specified map will not be transformed. + * If you want that behaviour, see {@link TransformedMap#transformedMap}. + *

      + * Each object is passed through the transformers as it is added to the + * Map. It is important not to use the original map after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

      + * If there are any elements already in the map being decorated, they + * are NOT transformed. + * + * @param the key type + * @param the value type + * @param map the map to transform, must not be null, typically empty + * @param keyTransformer the transformer for the map keys, null means no transformation + * @param valueTransformer the transformer for the map values, null means no transformation + * @return a transformed map backed by the given map + * @throws NullPointerException if the Map is null + */ + public static IterableMap transformedMap(final Map map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + return TransformedMap.transformingMap(map, keyTransformer, valueTransformer); + } + + /** + * Returns a fixed-sized map backed by the given map. + * Elements may not be added or removed from the returned map, but + * existing elements can be changed (for instance, via the + * {@link Map#put(Object,Object)} method). + * + * @param the key type + * @param the value type + * @param map the map whose size to fix, must not be null + * @return a fixed-size map backed by that map + * @throws NullPointerException if the Map is null + */ + public static IterableMap fixedSizeMap(final Map map) { + return FixedSizeMap.fixedSizeMap(map); + } + + /** + * Returns a "lazy" map whose values will be created on demand. + *

      + * When the key passed to the returned map's {@link Map#get(Object)} + * method is not present in the map, then the factory will be used + * to create a new object and that object will become the value + * associated with that key. + *

      + * For instance: + *

      +     * Factory factory = new Factory() {
      +     *     public Object create() {
      +     *         return new Date();
      +     *     }
      +     * }
      +     * Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
      +     * Object obj = lazyMap.get("test");
      +     * 
      + * + * After the above code is executed, obj will contain + * a new Date instance. Furthermore, that Date + * instance is the value for the "test" key in the map. + * + * @param the key type + * @param the value type + * @param map the map to make lazy, must not be null + * @param factory the factory for creating new objects, must not be null + * @return a lazy map backed by the given map + * @throws NullPointerException if the Map or Factory is null + */ + public static IterableMap lazyMap(final Map map, final Factory factory) { + return LazyMap.lazyMap(map, factory); + } + + /** + * Returns a "lazy" map whose values will be created on demand. + *

      + * When the key passed to the returned map's {@link Map#get(Object)} + * method is not present in the map, then the factory will be used + * to create a new object and that object will become the value + * associated with that key. The factory is a {@link Transformer} + * that will be passed the key which it must transform into the value. + *

      + * For instance: + *

      +     * Transformer factory = new Transformer() {
      +     *     public Object transform(Object mapKey) {
      +     *         return new File(mapKey);
      +     *     }
      +     * }
      +     * Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
      +     * Object obj = lazyMap.get("C:/dev");
      +     * 
      + * + * After the above code is executed, obj will contain + * a new File instance for the C drive dev directory. + * Furthermore, that File instance is the value for the + * "C:/dev" key in the map. + *

      + * If a lazy map is wrapped by a synchronized map, the result is a simple + * synchronized cache. When an object is not is the cache, the cache itself + * calls back to the factory Transformer to populate itself, all within the + * same synchronized block. + * + * @param the key type + * @param the value type + * @param map the map to make lazy, must not be null + * @param transformerFactory the factory for creating new objects, must not be null + * @return a lazy map backed by the given map + * @throws NullPointerException if the Map or Transformer is null + */ + public static IterableMap lazyMap(final Map map, + final Transformer transformerFactory) { + return LazyMap.lazyMap(map, transformerFactory); + } + + /** + * Returns a map that maintains the order of keys that are added + * backed by the given map. + *

      + * If a key is added twice, the order is determined by the first add. + * The order is observed through the keySet, values and entrySet. + * + * @param the key type + * @param the value type + * @param map the map to order, must not be null + * @return an ordered map backed by the given map + * @throws NullPointerException if the Map is null + */ + public static OrderedMap orderedMap(final Map map) { + return ListOrderedMap.listOrderedMap(map); + } + + /** + * Creates a mult-value map backed by the given map which returns + * collections of type ArrayList. + * + * @param the key type + * @param the value type + * @param map the map to decorate + * @return a multi-value map backed by the given map which returns ArrayLists of values. + * @see MultiValueMap + * @since 3.2 + * @deprecated since 4.1, use {@link MultiValuedMap} instead + */ + @Deprecated + public static MultiValueMap multiValueMap(final Map> map) { + return MultiValueMap.multiValueMap(map); + } + + /** + * Creates a multi-value map backed by the given map which returns + * collections of the specified type. + * + * @param the key type + * @param the value type + * @param the collection class type + * @param map the map to decorate + * @param collectionClass the type of collections to return from the map + * (must contain public no-arg constructor and extend Collection) + * @return a multi-value map backed by the given map which returns collections of the specified type + * @see MultiValueMap + * @since 3.2 + * @deprecated since 4.1, use {@link MultiValuedMap} instead + */ + @Deprecated + public static > MultiValueMap multiValueMap(final Map map, + final Class collectionClass) { + return MultiValueMap.multiValueMap(map, collectionClass); + } + + /** + * Creates a multi-value map backed by the given map which returns + * collections created by the specified collection factory. + * + * @param the key type + * @param the value type + * @param the collection class type + * @param map the map to decorate + * @param collectionFactory a factor which creates collection objects + * @return a multi-value map backed by the given map which returns collections + * created by the specified collection factory + * @see MultiValueMap + * @since 3.2 + * @deprecated since 4.1, use {@link MultiValuedMap} instead + */ + @Deprecated + public static > MultiValueMap multiValueMap(final Map map, + final Factory collectionFactory) { + return MultiValueMap.multiValueMap(map, collectionFactory); + } + + // SortedMap decorators + //----------------------------------------------------------------------- + /** + * Returns a synchronized sorted map backed by the given sorted map. + *

      + * You must manually synchronize on the returned buffer's iterator to + * avoid non-deterministic behavior: + * + *

      +     * Map m = MapUtils.synchronizedSortedMap(myMap);
      +     * Set s = m.keySet();  // outside synchronized block
      +     * synchronized (m) {  // synchronized on MAP!
      +     *     Iterator i = s.iterator();
      +     *     while (i.hasNext()) {
      +     *         process (i.next());
      +     *     }
      +     * }
      +     * 
      + * + * This method uses the implementation in {@link java.util.Collections Collections}. + * + * @param the key type + * @param the value type + * @param map the map to synchronize, must not be null + * @return a synchronized map backed by the given map + * @throws NullPointerException if the map is null + */ + public static SortedMap synchronizedSortedMap(final SortedMap map) { + return Collections.synchronizedSortedMap(map); + } + + /** + * Returns an unmodifiable sorted map backed by the given sorted map. + *

      + * This method uses the implementation in the decorators subpackage. + * + * @param the key type + * @param the value type + * @param map the sorted map to make unmodifiable, must not be null + * @return an unmodifiable map backed by the given map + * @throws NullPointerException if the map is null + */ + public static SortedMap unmodifiableSortedMap(final SortedMap map) { + return UnmodifiableSortedMap.unmodifiableSortedMap(map); + } + + /** + * Returns a predicated (validating) sorted map backed by the given map. + *

      + * Only objects that pass the tests in the given predicates can be added to the map. + * Trying to add an invalid object results in an IllegalArgumentException. + * Keys must pass the key predicate, values must pass the value predicate. + * It is important not to use the original map after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the key type + * @param the value type + * @param map the map to predicate, must not be null + * @param keyPred the predicate for keys, null means no check + * @param valuePred the predicate for values, null means no check + * @return a predicated map backed by the given map + * @throws NullPointerException if the SortedMap is null + */ + public static SortedMap predicatedSortedMap(final SortedMap map, + final Predicate keyPred, final Predicate valuePred) { + return PredicatedSortedMap.predicatedSortedMap(map, keyPred, valuePred); + } + + /** + * Returns a transformed sorted map backed by the given map. + *

      + * This method returns a new sorted map (decorating the specified map) that + * will transform any new entries added to it. + * Existing entries in the specified map will not be transformed. + * If you want that behaviour, see {@link TransformedSortedMap#transformedSortedMap}. + *

      + * Each object is passed through the transformers as it is added to the + * Map. It is important not to use the original map after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

      + * If there are any elements already in the map being decorated, they + * are NOT transformed. + * + * @param the key type + * @param the value type + * @param map the map to transform, must not be null, typically empty + * @param keyTransformer the transformer for the map keys, null means no transformation + * @param valueTransformer the transformer for the map values, null means no transformation + * @return a transformed map backed by the given map + * @throws NullPointerException if the SortedMap is null + */ + public static SortedMap transformedSortedMap(final SortedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + return TransformedSortedMap.transformingSortedMap(map, keyTransformer, valueTransformer); + } + + /** + * Returns a fixed-sized sorted map backed by the given sorted map. + * Elements may not be added or removed from the returned map, but + * existing elements can be changed (for instance, via the + * {@link Map#put(Object,Object)} method). + * + * @param the key type + * @param the value type + * @param map the map whose size to fix, must not be null + * @return a fixed-size map backed by that map + * @throws NullPointerException if the SortedMap is null + */ + public static SortedMap fixedSizeSortedMap(final SortedMap map) { + return FixedSizeSortedMap.fixedSizeSortedMap(map); + } + + /** + * Returns a "lazy" sorted map whose values will be created on demand. + *

      + * When the key passed to the returned map's {@link Map#get(Object)} + * method is not present in the map, then the factory will be used + * to create a new object and that object will become the value + * associated with that key. + *

      + * For instance: + * + *

      +     * Factory factory = new Factory() {
      +     *     public Object create() {
      +     *         return new Date();
      +     *     }
      +     * }
      +     * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
      +     * Object obj = lazy.get("test");
      +     * 
      + * + * After the above code is executed, obj will contain + * a new Date instance. Furthermore, that Date + * instance is the value for the "test" key. + * + * @param the key type + * @param the value type + * @param map the map to make lazy, must not be null + * @param factory the factory for creating new objects, must not be null + * @return a lazy map backed by the given map + * @throws NullPointerException if the SortedMap or Factory is null + */ + public static SortedMap lazySortedMap(final SortedMap map, final Factory factory) { + return LazySortedMap.lazySortedMap(map, factory); + } + + /** + * Returns a "lazy" sorted map whose values will be created on demand. + *

      + * When the key passed to the returned map's {@link Map#get(Object)} + * method is not present in the map, then the factory will be used + * to create a new object and that object will become the value + * associated with that key. The factory is a {@link Transformer} + * that will be passed the key which it must transform into the value. + *

      + * For instance: + *

      +     * Transformer factory = new Transformer() {
      +     *     public Object transform(Object mapKey) {
      +     *         return new File(mapKey);
      +     *     }
      +     * }
      +     * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
      +     * Object obj = lazy.get("C:/dev");
      +     * 
      + * + * After the above code is executed, obj will contain + * a new File instance for the C drive dev directory. + * Furthermore, that File instance is the value for the + * "C:/dev" key in the map. + *

      + * If a lazy map is wrapped by a synchronized map, the result is a simple + * synchronized cache. When an object is not is the cache, the cache itself + * calls back to the factory Transformer to populate itself, all within the + * same synchronized block. + * + * @param the key type + * @param the value type + * @param map the map to make lazy, must not be null + * @param transformerFactory the factory for creating new objects, must not be null + * @return a lazy map backed by the given map + * @throws NullPointerException if the Map or Transformer is null + */ + public static SortedMap lazySortedMap(final SortedMap map, + final Transformer transformerFactory) { + return LazySortedMap.lazySortedMap(map, transformerFactory); + } + + /** + * Populates a Map using the supplied Transformer to transform the elements + * into keys, using the unaltered element as the value in the Map. + * + * @param the key type + * @param the value type + * @param map the Map to populate. + * @param elements the Iterable containing the input values for the map. + * @param keyTransformer the Transformer used to transform the element into a key value + * @throws NullPointerException if the map, elements or transformer are null + */ + public static void populateMap(final Map map, final Iterable elements, + final Transformer keyTransformer) { + populateMap(map, elements, keyTransformer, TransformerUtils.nopTransformer()); + } + + /** + * Populates a Map using the supplied Transformers to transform the elements + * into keys and values. + * + * @param the key type + * @param the value type + * @param the type of object contained in the {@link Iterable} + * @param map the Map to populate. + * @param elements the Iterable containing the input values for the map. + * @param keyTransformer the Transformer used to transform the element into a key value + * @param valueTransformer the Transformer used to transform the element into a value + * @throws NullPointerException if the map, elements or transformers are null + */ + public static void populateMap(final Map map, final Iterable elements, + final Transformer keyTransformer, + final Transformer valueTransformer) { + final Iterator iter = elements.iterator(); + while (iter.hasNext()) { + final E temp = iter.next(); + map.put(keyTransformer.transform(temp), valueTransformer.transform(temp)); + } + } + + /** + * Populates a MultiMap using the supplied Transformer to transform the elements + * into keys, using the unaltered element as the value in the MultiMap. + * + * @param the key type + * @param the value type + * @param map the MultiMap to populate. + * @param elements the Iterable to use as input values for the map. + * @param keyTransformer the Transformer used to transform the element into a key value + * @throws NullPointerException if the map, elements or transformer are null + */ + public static void populateMap(final MultiMap map, final Iterable elements, + final Transformer keyTransformer) { + populateMap(map, elements, keyTransformer, TransformerUtils.nopTransformer()); + } + + /** + * Populates a MultiMap using the supplied Transformers to transform the elements + * into keys and values. + * + * @param the key type + * @param the value type + * @param the type of object contained in the {@link Iterable} + * @param map the MultiMap to populate. + * @param elements the Iterable containing the input values for the map. + * @param keyTransformer the Transformer used to transform the element into a key value + * @param valueTransformer the Transformer used to transform the element into a value + * @throws NullPointerException if the map, collection or transformers are null + */ + public static void populateMap(final MultiMap map, final Iterable elements, + final Transformer keyTransformer, + final Transformer valueTransformer) { + final Iterator iter = elements.iterator(); + while (iter.hasNext()) { + final E temp = iter.next(); + map.put(keyTransformer.transform(temp), valueTransformer.transform(temp)); + } + } + + /** + * Get the specified {@link Map} as an {@link IterableMap}. + * + * @param the key type + * @param the value type + * @param map to wrap if necessary. + * @return IterableMap + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static IterableMap iterableMap(final Map map) { + if (map == null) { + throw new NullPointerException("Map must not be null"); + } + return map instanceof IterableMap ? (IterableMap) map : new AbstractMapDecorator(map) {}; + } + + /** + * Get the specified {@link SortedMap} as an {@link IterableSortedMap}. + * + * @param the key type + * @param the value type + * @param sortedMap to wrap if necessary + * @return {@link IterableSortedMap} + * @throws NullPointerException if sortedMap is null + * @since 4.0 + */ + public static IterableSortedMap iterableSortedMap(final SortedMap sortedMap) { + if (sortedMap == null) { + throw new NullPointerException("Map must not be null"); + } + return sortedMap instanceof IterableSortedMap ? (IterableSortedMap) sortedMap : + new AbstractSortedMapDecorator(sortedMap) {}; + } + +} diff --git a/src/org/apache/commons/collections4/MultiMap.java b/src/org/apache/commons/collections4/MultiMap.java new file mode 100644 index 0000000..079a636 --- /dev/null +++ b/src/org/apache/commons/collections4/MultiMap.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; + +/** + * Defines a map that holds a collection of values against each key. + *

      + * A MultiMap is a Map with slightly different semantics. + * Putting a value into the map will add the value to a Collection at that key. + * Getting a value will return a Collection, holding all the values put to that key. + *

      + * For example: + *

      + * MultiMap mhm = new MultiValueMap();
      + * mhm.put(key, "A");
      + * mhm.put(key, "B");
      + * mhm.put(key, "C");
      + * Collection coll = (Collection) mhm.get(key);
      + *

      + * coll will be a collection containing "A", "B", "C". + *

      + * NOTE: Additional methods were added to this interface in Commons Collections 3.1. + * These were added solely for documentation purposes and do not change the interface + * as they were defined in the superinterface Map anyway. + * + * @since 2.0 + * @version $Id: MultiMap.java 1683018 2015-06-01 22:41:31Z tn $ + * @deprecated since 4.1, use {@link MultiValuedMap} instead + */ +@Deprecated +public interface MultiMap extends IterableMap { + + /** + * Removes a specific value from map. + *

      + * The item is removed from the collection mapped to the specified key. + * Other values attached to that key are unaffected. + *

      + * If the last value for a key is removed, implementations typically + * return null from a subsequent get(Object), however + * they may choose to return an empty collection. + * + * @param key the key to remove from + * @param item the item to remove + * @return {@code true} if the mapping was removed, {@code false} otherwise + * @throws UnsupportedOperationException if the map is unmodifiable + * @throws ClassCastException if the key or value is of an invalid type + * @throws NullPointerException if the key or value is null and null is invalid + * @since 4.0 (signature in previous releases: V remove(K, V)) + */ + boolean removeMapping(K key, V item); + + //----------------------------------------------------------------------- + /** + * Gets the number of keys in this map. + *

      + * Implementations typically return only the count of keys in the map + * This cannot be mandated due to backwards compatibility of this interface. + * + * @return the number of key-collection mappings in this map + */ + int size(); + + /** + * Gets the collection of values associated with the specified key. + *

      + * The returned value will implement Collection. Implementations + * are free to declare that they return Collection subclasses + * such as List or Set. + *

      + * Implementations typically return null if no values have + * been mapped to the key, however the implementation may choose to + * return an empty collection. + *

      + * Implementations may choose to return a clone of the internal collection. + * + * @param key the key to retrieve + * @return the Collection of values, implementations should + * return null for no mapping, but may return an empty collection + * @throws ClassCastException if the key is of an invalid type + * @throws NullPointerException if the key is null and null keys are invalid + */ + Object get(Object key); // Cannot use get(K key) as that does not properly implement Map#get + + /** + * Checks whether the map contains the value specified. + *

      + * Implementations typically check all collections against all keys for the value. + * This cannot be mandated due to backwards compatibility of this interface. + * + * @param value the value to search for + * @return true if the map contains the value + * @throws ClassCastException if the value is of an invalid type + * @throws NullPointerException if the value is null and null value are invalid + */ + boolean containsValue(Object value); + + /** + * Adds the value to the collection associated with the specified key. + *

      + * Unlike a normal Map the previous value is not replaced. + * Instead the new value is added to the collection stored against the key. + * The collection may be a List, Set or other + * collection dependent on implementation. + * + * @param key the key to store against + * @param value the value to add to the collection at the key + * @return typically the value added if the map changed and null if the map did not change + * @throws UnsupportedOperationException if the map is unmodifiable + * @throws ClassCastException if the key or value is of an invalid type + * @throws NullPointerException if the key or value is null and null is invalid + * @throws IllegalArgumentException if the key or value is invalid + */ + Object put(K key, Object value); + + /** + * Removes all values associated with the specified key. + *

      + * Implementations typically return null from a subsequent + * get(Object), however they may choose to return an empty collection. + * + * @param key the key to remove values from + * @return the Collection of values removed, implementations should + * return null for no mapping found, but may return an empty collection + * @throws UnsupportedOperationException if the map is unmodifiable + * @throws ClassCastException if the key is of an invalid type + * @throws NullPointerException if the key is null and null keys are invalid + */ + Object remove(Object key); // Cannot use remove(K key) as that does not properly implement Map#remove + + /** + * Gets a collection containing all the values in the map. + *

      + * Implementations typically return a collection containing the combination + * of values from all keys. + * This cannot be mandated due to backwards compatibility of this interface. + * + * @return a collection view of the values contained in this map + */ + Collection values(); + +} diff --git a/src/org/apache/commons/collections4/MultiMapUtils.java b/src/org/apache/commons/collections4/MultiMapUtils.java new file mode 100644 index 0000000..95d9b86 --- /dev/null +++ b/src/org/apache/commons/collections4/MultiMapUtils.java @@ -0,0 +1,254 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.collections4.bag.HashBag; +import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; +import org.apache.commons.collections4.multimap.HashSetValuedHashMap; +import org.apache.commons.collections4.multimap.TransformedMultiValuedMap; +import org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap; + +/** + * Provides utility methods and decorators for {@link MultiValuedMap} instances. + *

      + * It contains various type safe and null safe methods. Additionally, it provides + * the following decorators: + *

        + *
      • {@link #unmodifiableMultiValuedMap(MultiValuedMap)}
      • + *
      • {@link #transformedMultiValuedMap(MultiValuedMap, Transformer, Transformer)}
      • + *
      + * + * @since 4.1 + * @version $Id: MultiMapUtils.java 1715302 2015-11-19 23:08:01Z tn $ + */ +public class MultiMapUtils { + + /** + * MultiMapUtils should not normally be instantiated. + */ + private MultiMapUtils() {} + + /** + * An empty {@link UnmodifiableMultiValuedMap}. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP = + UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0)); + + /** + * Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety. + * + * @param the type of key in the map + * @param the type of value in the map + * @return immutable and empty MultiValuedMap + */ + @SuppressWarnings("unchecked") + public static MultiValuedMap emptyMultiValuedMap() { + return EMPTY_MULTI_VALUED_MAP; + } + + // Null safe methods + + /** + * Returns an immutable empty MultiValuedMap if the argument is + * null, or the argument itself otherwise. + * + * @param the type of key in the map + * @param the type of value in the map + * @param map the map, may be null + * @return an empty {@link MultiValuedMap} if the argument is null + */ + @SuppressWarnings("unchecked") + public static MultiValuedMap emptyIfNull(final MultiValuedMap map) { + return map == null ? EMPTY_MULTI_VALUED_MAP : map; + } + + /** + * Null-safe check if the specified MultiValuedMap is empty. + *

      + * If the provided map is null, returns true. + * + * @param map the map to check, may be null + * @return true if the map is empty or null + */ + public static boolean isEmpty(final MultiValuedMap map) { + return map == null || map.isEmpty(); + } + + // Null safe getters + // ------------------------------------------------------------------------- + + /** + * Gets a Collection from MultiValuedMap in a null-safe manner. + * + * @param the key type + * @param the value type + * @param map the {@link MultiValuedMap} to use + * @param key the key to look up + * @return the Collection in the {@link MultiValuedMap}, or null if input map is null + */ + public static Collection getCollection(final MultiValuedMap map, final K key) { + if (map != null) { + return map.get(key); + } + return null; + } + + // TODO: review the getValuesAsXXX methods - depending on the actual MultiValuedMap type, changes + // to the returned collection might update the backing map. This should be clarified and/or prevented. + + /** + * Gets a List from MultiValuedMap in a null-safe manner. + * + * @param the key type + * @param the value type + * @param map the {@link MultiValuedMap} to use + * @param key the key to look up + * @return the Collection in the {@link MultiValuedMap} as List, or null if input map is null + */ + public static List getValuesAsList(final MultiValuedMap map, final K key) { + if (map != null) { + Collection col = map.get(key); + if (col instanceof List) { + return (List) col; + } + return new ArrayList(col); + } + return null; + } + + /** + * Gets a Set from MultiValuedMap in a null-safe manner. + * + * @param the key type + * @param the value type + * @param map the {@link MultiValuedMap} to use + * @param key the key to look up + * @return the Collection in the {@link MultiValuedMap} as Set, or null if input map is null + */ + public static Set getValuesAsSet(final MultiValuedMap map, final K key) { + if (map != null) { + Collection col = map.get(key); + if (col instanceof Set) { + return (Set) col; + } + return new HashSet(col); + } + return null; + } + + /** + * Gets a Bag from MultiValuedMap in a null-safe manner. + * + * @param the key type + * @param the value type + * @param map the {@link MultiValuedMap} to use + * @param key the key to look up + * @return the Collection in the {@link MultiValuedMap} as Bag, or null if input map is null + */ + public static Bag getValuesAsBag(final MultiValuedMap map, final K key) { + if (map != null) { + Collection col = map.get(key); + if (col instanceof Bag) { + return (Bag) col; + } + return new HashBag(col); + } + return null; + } + + // Factory Methods + // ----------------------------------------------------------------------- + + /** + * Creates a {@link ListValuedMap} with an {@link java.util.ArrayList ArrayList} as + * collection class to store the values mapped to a key. + * + * @param the key type + * @param the value type + * @return a new ListValuedMap + */ + public static ListValuedMap newListValuedHashMap() { + return new ArrayListValuedHashMap(); + } + + /** + * Creates a {@link SetValuedMap} with an {@link java.util.HashSet HashSet} as + * collection class to store the values mapped to a key. + * + * @param the key type + * @param the value type + * @return a new {@link SetValuedMap} + */ + public static SetValuedMap newSetValuedHashMap() { + return new HashSetValuedHashMap(); + } + + // MultiValuedMap Decorators + // ----------------------------------------------------------------------- + + /** + * Returns an UnmodifiableMultiValuedMap backed by the given + * map. + * + * @param the key type + * @param the value type + * @param map the {@link MultiValuedMap} to decorate, must not be null + * @return an unmodifiable {@link MultiValuedMap} backed by the provided map + * @throws NullPointerException if map is null + */ + public static MultiValuedMap unmodifiableMultiValuedMap( + final MultiValuedMap map) { + return UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(map); + } + + /** + * Returns a TransformedMultiValuedMap backed by the given map. + *

      + * This method returns a new MultiValuedMap (decorating the + * specified map) that will transform any new entries added to it. Existing + * entries in the specified map will not be transformed. If you want that + * behaviour, see {@link TransformedMultiValuedMap#transformedMap}. + *

      + * Each object is passed through the transformers as it is added to the Map. + * It is important not to use the original map after invoking this method, + * as it is a back door for adding untransformed objects. + *

      + * If there are any elements already in the map being decorated, they are + * NOT transformed. + * + * @param the key type + * @param the value type + * @param map the {@link MultiValuedMap} to transform, must not be null, typically empty + * @param keyTransformer the transformer for the map keys, null means no transformation + * @param valueTransformer the transformer for the map values, null means no transformation + * @return a transformed MultiValuedMap backed by the given map + * @throws NullPointerException if map is null + */ + public static MultiValuedMap transformedMultiValuedMap(final MultiValuedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + return TransformedMultiValuedMap.transformingMap(map, keyTransformer, valueTransformer); + } + +} diff --git a/src/org/apache/commons/collections4/MultiSet.java b/src/org/apache/commons/collections4/MultiSet.java new file mode 100644 index 0000000..fd51b63 --- /dev/null +++ b/src/org/apache/commons/collections4/MultiSet.java @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +/** + * Defines a collection that counts the number of times an object appears in + * the collection. + *

      + * Suppose you have a MultiSet that contains {a, a, b, c}. + * Calling {@link #getCount(Object)} on a would return 2, while + * calling {@link #uniqueSet()} would return {a, b, c}. + * + * @param the type held in the multiset + * @since 4.1 + * @version $Id: MultiSet.java 1714424 2015-11-15 10:06:16Z tn $ + */ +public interface MultiSet extends Collection { + + /** + * Returns the number of occurrences of the given object currently + * in the MultiSet. If the object does not exist in the multiset, + * return 0. + * + * @param object the object to search for + * @return the number of occurrences of the object, zero if not found + */ + int getCount(Object object); + + /** + * Sets the number of occurrences of the specified object in the MultiSet + * to the given count. + *

      + * If the provided count is zero, the object will be removed from the + * {@link #uniqueSet()}. + * + * @param object the object to update + * @param count the number of occurrences of the object + * @return the number of occurrences of the object before this operation, zero + * if the object was not contained in the multiset + * @throws IllegalArgumentException if count is negative + */ + int setCount(E object, int count); + + /** + * Adds one copy of the specified object to the MultiSet. + *

      + * If the object is already in the {@link #uniqueSet()} then increment its + * count as reported by {@link #getCount(Object)}. Otherwise add it to the + * {@link #uniqueSet()} and report its count as 1. + * + * @param object the object to add + * @return true always, as the size of the MultiSet is increased + * in any case + */ + @Override + boolean add(E object); + + /** + * Adds a number of occurrences of the specified object to the MultiSet. + *

      + * If the object is already in the {@link #uniqueSet()} then increment its + * count as reported by {@link #getCount(Object)}. Otherwise add it to the + * {@link #uniqueSet()} and report its count as occurrences. + * + * @param object the object to add + * @param occurrences the number of occurrences to add, may be zero, + * in which case no change is made to the multiset + * @return the number of occurrences of the object in the multiset before + * this operation; possibly zero + * @throws IllegalArgumentException if occurrences is negative + */ + int add(E object, int occurrences); + + /** + * Removes one occurrence of the given object from the MultiSet. + *

      + * If the number of occurrences after this operations is reduced + * to zero, the object will be removed from the {@link #uniqueSet()}. + * + * @param object the object to remove + * @return true if this call changed the collection + */ + @Override + boolean remove(Object object); + + /** + * Removes a number of occurrences of the specified object from the MultiSet. + *

      + * If the number of occurrences to remove is greater than the actual number of + * occurrences in the multiset, the object will be removed from the multiset. + * + * @param object the object to remove + * @param occurrences the number of occurrences to remove, may be zero, + * in which case no change is made to the multiset + * @return the number of occurrences of the object in the multiset + * before the operation; possibly zero + * @throws IllegalArgumentException if occurrences is negative + */ + int remove(Object object, int occurrences); + + /** + * Returns a {@link Set} of unique elements in the MultiSet. + *

      + * Uniqueness constraints are the same as those in {@link java.util.Set}. + *

      + * The returned set is backed by this multiset, so any change to either + * is immediately reflected in the other. Only removal operations are + * supported, in which case all occurrences of the element are removed + * from the backing multiset. + * + * @return the Set of unique MultiSet elements + */ + Set uniqueSet(); + + /** + * Returns a {@link Set} of all entries contained in the MultiSet. + *

      + * The returned set is backed by this multiset, so any change to either + * is immediately reflected in the other. + * + * @return the Set of MultiSet entries + */ + Set> entrySet(); + + /** + * Returns an {@link Iterator} over the entire set of members, + * including copies due to cardinality. This iterator is fail-fast + * and will not tolerate concurrent modifications. + * + * @return iterator over all elements in the MultiSet + */ + @Override + Iterator iterator(); + + /** + * Returns the total number of items in the MultiSet. + * + * @return the total size of the multiset + */ + @Override + int size(); + + /** + * Returns true if the MultiSet contains at least one + * occurrence for each element contained in the given collection. + * + * @param coll the collection to check against + * @return true if the MultiSet contains all the collection + */ + @Override + boolean containsAll(Collection coll); + + /** + * Remove all occurrences of all elements from this MultiSet represented + * in the given collection. + * + * @param coll the collection of elements to remove + * @return true if this call changed the multiset + */ + @Override + boolean removeAll(Collection coll); + + /** + * Remove any elements of this MultiSet that are not contained in the + * given collection. + * + * @param coll the collection of elements to retain + * @return true if this call changed the multiset + */ + @Override + boolean retainAll(Collection coll); + + /** + * Compares this MultiSet to another object. + *

      + * This MultiSet equals another object if it is also a MultiSet + * that contains the same number of occurrences of the same elements. + * + * @param obj the object to compare to + * @return true if equal + */ + @Override + boolean equals(Object obj); + + /** + * Gets a hash code for the MultiSet compatible with the definition of equals. + * The hash code is defined as the sum total of a hash code for each element. + * The per element hash code is defined as + * (e==null ? 0 : e.hashCode()) ^ noOccurances). + * + * @return the hash code of the MultiSet + */ + @Override + int hashCode(); + + /** + * An unmodifiable entry for an element and its occurrence as contained in a MultiSet. + *

      + * The {@link MultiSet#entrySet()} method returns a view of the multiset whose elements + * implements this interface. + * + * @param the element type + */ + interface Entry { + + /** + * Returns the element corresponding to this entry. + * + * @return the element corresponding to this entry + */ + E getElement(); + + /** + * Returns the number of occurrences for the element of this entry. + * + * @return the number of occurrences of the element + */ + int getCount(); + + /** + * Compares the specified object with this entry for equality. + * Returns true if the given object is also a multiset entry + * and the two entries represent the same element with the same + * number of occurrences. + *

      + * More formally, two entries e1 and e2 represent + * the same mapping if + *

      +         *     (e1.getElement()==null ? e2.getElement()==null
      +         *                            : e1.getElement().equals(e2.getElement())) &&
      +         *     (e1.getCount()==e2.getCount())
      +         * 
      + * + * @param o object to be compared for equality with this multiset entry + * @return true if the specified object is equal to this multiset entry + */ + @Override + boolean equals(Object o); + + /** + * Returns the hash code value for this multiset entry. + *

      + * The hash code of a multiset entry e is defined to be: + *

      +         *      (e==null ? 0 : e.hashCode()) ^ noOccurances)
      +         * 
      + * + * @return the hash code value for this multiset entry + */ + @Override + int hashCode(); + } + +} diff --git a/src/org/apache/commons/collections4/MultiSetUtils.java b/src/org/apache/commons/collections4/MultiSetUtils.java new file mode 100644 index 0000000..ee47088 --- /dev/null +++ b/src/org/apache/commons/collections4/MultiSetUtils.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import org.apache.commons.collections4.multiset.HashMultiSet; +import org.apache.commons.collections4.multiset.PredicatedMultiSet; +import org.apache.commons.collections4.multiset.SynchronizedMultiSet; +import org.apache.commons.collections4.multiset.UnmodifiableMultiSet; + +/** + * Provides utility methods and decorators for {@link MultiSet} instances. + * + * @since 4.1 + * @version $Id: MultiSetUtils.java 1714424 2015-11-15 10:06:16Z tn $ + */ +public class MultiSetUtils { + + /** + * An empty unmodifiable multiset. + */ + @SuppressWarnings("rawtypes") // OK, empty multiset is compatible with any type + public static final MultiSet EMPTY_MULTISET = + UnmodifiableMultiSet.unmodifiableMultiSet(new HashMultiSet()); + + /** + * Instantiation of MultiSetUtils is not intended or required. + */ + private MultiSetUtils() {} + + //----------------------------------------------------------------------- + /** + * Returns a synchronized (thread-safe) multiset backed by the given multiset. + * In order to guarantee serial access, it is critical that all access to the + * backing multiset is accomplished through the returned multiset. + *

      + * It is imperative that the user manually synchronize on the returned multiset + * when iterating over it: + * + *

      +     * MultiSet multiset = MultiSetUtils.synchronizedMultiSet(new HashMultiSet());
      +     * ...
      +     * synchronized(multiset) {
      +     *     Iterator i = multiset.iterator(); // Must be in synchronized block
      +     *     while (i.hasNext())
      +     *         foo(i.next());
      +     *     }
      +     * }
      +     * 
      + * + * Failure to follow this advice may result in non-deterministic behavior. + * + * @param the element type + * @param multiset the multiset to synchronize, must not be null + * @return a synchronized multiset backed by that multiset + * @throws NullPointerException if the MultiSet is null + */ + public static MultiSet synchronizedMultiSet(final MultiSet multiset) { + return SynchronizedMultiSet.synchronizedMultiSet(multiset); + } + + /** + * Returns an unmodifiable view of the given multiset. Any modification attempts + * to the returned multiset will raise an {@link UnsupportedOperationException}. + * + * @param the element type + * @param multiset the multiset whose unmodifiable view is to be returned, must not be null + * @return an unmodifiable view of that multiset + * @throws NullPointerException if the MultiSet is null + */ + public static MultiSet unmodifiableMultiSet(final MultiSet multiset) { + return UnmodifiableMultiSet.unmodifiableMultiSet(multiset); + } + + /** + * Returns a predicated (validating) multiset backed by the given multiset. + *

      + * Only objects that pass the test in the given predicate can be added to + * the multiset. Trying to add an invalid object results in an + * IllegalArgumentException. It is important not to use the original multiset + * after invoking this method, as it is a backdoor for adding invalid + * objects. + * + * @param the element type + * @param multiset the multiset to predicate, must not be null + * @param predicate the predicate for the multiset, must not be null + * @return a predicated multiset backed by the given multiset + * @throws NullPointerException if the MultiSet or Predicate is null + */ + public static MultiSet predicatedMultiSet(final MultiSet multiset, + final Predicate predicate) { + return PredicatedMultiSet.predicatedMultiSet(multiset, predicate); + } + + /** + * Get an empty MultiSet. + * + * @param the element type + * @return an empty MultiSet + */ + @SuppressWarnings("unchecked") // OK, empty multiset is compatible with any type + public static MultiSet emptyMultiSet() { + return EMPTY_MULTISET; + } + +} diff --git a/src/org/apache/commons/collections4/MultiValuedMap.java b/src/org/apache/commons/collections4/MultiValuedMap.java new file mode 100644 index 0000000..1021822 --- /dev/null +++ b/src/org/apache/commons/collections4/MultiValuedMap.java @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Defines a map that holds a collection of values against each key. + *

      + * A {@code MultiValuedMap} is a Map with slightly different semantics: + *

        + *
      • Putting a value into the map will add the value to a {@link Collection} at that key.
      • + *
      • Getting a value will return a {@link Collection}, holding all the values put to that key.
      • + *
      + *

      + * For example: + *

      + * MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
      + * map.put(key, "A");
      + * map.put(key, "B");
      + * map.put(key, "C");
      + * Collection<String> coll = map.get(key);
      + * 
      + *

      + * coll will be a collection containing "A", "B", "C". + *

      + * + * @since 4.1 + * @version $Id: MultiValuedMap.java 1716537 2015-11-25 20:27:24Z tn $ + */ +public interface MultiValuedMap { + // Query operations + + /** + * Gets the total size of the map. + *

      + * Implementations would return the total size of the map which is the count + * of the values from all keys. + * + * @return the total size of the map + */ + int size(); + + /** + * Returns {@code true} if this map contains no key-value mappings. + * + * @return {@code true} if this map contains no key-value mappings + */ + boolean isEmpty(); + + /** + * Returns {@code true} if this map contains a mapping for the specified + * key. More formally, returns {@code true} if and only if this map contains + * a mapping for a key {@code k} such that {@code (key==null ? k==null : key.equals(k))}. + * (There can be at most one such mapping.) + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified key + * @throws NullPointerException if the specified key is null and this map + * does not permit null keys (optional) + */ + boolean containsKey(Object key); + + /** + * Checks whether the map contains at least one mapping for the specified value. + * + * @param value the value to search for + * @return true if the map contains the value + * @throws NullPointerException if the value is null and null values are not supported + * by the used collection types (optional) + */ + boolean containsValue(Object value); + + /** + * Checks whether the map contains a mapping for the specified key and value. + * + * @param key the key to search for + * @param value the value to search for + * @return true if the map contains the value + */ + boolean containsMapping(Object key, Object value); + + /** + * Returns a view collection of the values associated with the specified key. + *

      + * This method will return an empty collection if {@link #containsKey(Object)} + * returns {@code false}. Changes to the returned collection will update the underlying + * {@code MultiValuedMap} and vice-versa. + * + * @param key the key to retrieve + * @return the {@code Collection} of values, implementations should + * return an empty collection for no mapping + * @throws NullPointerException if the key is null and null keys are invalid (optional) + */ + Collection get(K key); + + // Modification operations + + /** + * Adds a key-value mapping to this multi-valued map. + *

      + * Unlike a normal {@code Map} the previous value is not replaced. + * Instead the new value is added to the collection stored against the key. + * Depending on the collection type used, duplicate key-value mappings may + * be allowed. + *

      + * The method will return {@code true} if the size of the multi-valued map + * has been increased because of this operation. + * + * @param key the key to store against + * @param value the value to add to the collection at the key + * @return true if the map changed as a result of this put operation, or false + * if the map already contained the key-value mapping and the collection + * type does not allow duplicate values, e.g. when using a Set + * @throws UnsupportedOperationException if the put operation is not supported by + * this multi-valued map, e.g. if it is unmodifiable + * @throws NullPointerException if the key or value is null and null is invalid (optional) + * @throws IllegalArgumentException if some aspect of the specified key or value prevents + * it from being stored in this multi-valued map + */ + boolean put(K key, V value); + + /** + * Adds a mapping to the specified key for all values contained in the given Iterable. + * + * @param key the key to store against + * @param values the values to add to the collection at the key, may not be null + * @return true if the map changed as a result of this operation + * @throws NullPointerException if the specified iterable is null, or if this map + * does not permit null keys or values, and the specified key or values contain + * null (optional) + */ + boolean putAll(K key, Iterable values); + + /** + * Copies all mappings from the specified map to this multi-valued map + * (optional operation). + *

      + * The effect of this call is equivalent to that of calling + * {@link #put(Object,Object) put(k, v)} on this map once for each mapping + * from key {@code k} to value {@code v} in the specified map. + *

      + * The behavior of this operation is undefined if the specified map is modified + * while the operation is in progress. + * + * @param map mappings to be stored in this map, may not be null + * @return true if the map changed as a result of this operation + * @throws UnsupportedOperationException if the {@code putAll} operation is + * not supported by this map + * @throws NullPointerException if the specified map is null, or if this map + * does not permit null keys or values, and the specified map + * contains null keys or values (optional) + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + boolean putAll(Map map); + + /** + * Copies all mappings from the specified map to this multi-valued map + * (optional operation). + *

      + * The effect of this call is equivalent to that of calling + * {@link #put(Object,Object) put(k, v)} on this map once for each + * mapping from key {@code k} to value {@code v} in the specified map. + *

      + * The behavior of this operation is undefined if the specified map is modified + * while the operation is in progress. + * + * @param map mappings to be stored in this map, may not be null + * @return true if the map changed as a result of this operation + * @throws UnsupportedOperationException if the {@code putAll} operation is + * not supported by this map + * @throws NullPointerException if the specified map is null, or if this map + * does not permit null keys or values, and the specified map + * contains null keys or values (optional) + * @throws IllegalArgumentException if some property of a key or value in + * the specified map prevents it from being stored in this map + */ + boolean putAll(MultiValuedMap map); + + /** + * Removes all values associated with the specified key. + *

      + * The returned collection may be modifiable, but updates will not be propagated + * to this multi-valued map. In case no mapping was stored for the specified + * key, an empty, unmodifiable collection will be returned. + * + * @param key the key to remove values from + * @return the values that were removed + * @throws UnsupportedOperationException if the map is unmodifiable + * @throws NullPointerException if the key is null and null keys are invalid (optional) + */ + Collection remove(Object key); + + /** + * Removes a key-value mapping from the map. + *

      + * The item is removed from the collection mapped to the specified key. + * Other values attached to that key are unaffected. + *

      + * If the last value for a key is removed, implementations typically return + * an empty collection from a subsequent get(Object). + * + * @param key the key to remove from + * @param item the item to remove + * @return true if the mapping was removed, false otherwise + * @throws UnsupportedOperationException if the map is unmodifiable + * @throws NullPointerException if the key or value is null and null is invalid (optional) + */ + boolean removeMapping(Object key, Object item); + + /** + * Removes all of the mappings from this map (optional operation). + *

      + * The map will be empty after this call returns. + * + * @throws UnsupportedOperationException if the map is unmodifiable + */ + void clear(); + + // Views + + /** + * Returns a {@link Collection} view of the mappings contained in this multi-valued map. + *

      + * The collection is backed by the map, so changes to the map are reflected + * in the collection, and vice-versa. + * + * @return a set view of the mappings contained in this map + */ + Collection> entries(); + + /** + * Returns a {@link MultiSet} view of the keys contained in this multi-valued map. + *

      + * The {@link MultiSet#getCount(Object)} method of the returned multiset will give + * the same result a calling {@code get(Object).size()} for the same key. + *

      + * This multiset is backed by the map, so any changes in the map are reflected in + * the multiset. + * + * @return a multiset view of the keys contained in this map + */ + MultiSet keys(); + + /** + * Returns a {@link Set} view of the keys contained in this multi-valued map. + *

      + * 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 result of the iteration is 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 set view of the keys contained in this map + */ + Set keySet(); + + /** + * Gets a {@link Collection} view of all values contained in this multi-valued map. + *

      + * Implementations typically return a collection containing the combination + * of values from all keys. + * + * @return a collection view of the values contained in this multi-valued map + */ + Collection values(); + + /** + * Returns a view of this multi-valued map as a {@code Map} from each distinct + * key to the non-empty collection of that key's associated values. + *

      + * Note that {@code this.asMap().get(k)} is equivalent to {@code this.get(k)} + * only when {@code k} is a key contained in the multi-valued map; otherwise it + * returns {@code null} as opposed to an empty collection. + *

      + * Changes to the returned map or the collections that serve as its values + * will update the underlying multi-valued map, and vice versa. The map does + * not support {@code put} or {@code putAll}, nor do its entries support + * {@link Map.Entry#setValue setValue}. + * + * @return a map view of the mappings in this multi-valued map + */ + Map> asMap(); + + // Iterators + + /** + * Obtains a MapIterator over this multi-valued map. + *

      + * A map iterator is an efficient way of iterating over maps. There is no + * need to access the entries collection or use {@code Map.Entry} objects. + * + * @return a map iterator + */ + MapIterator mapIterator(); + +} diff --git a/src/org/apache/commons/collections4/OrderedBidiMap.java b/src/org/apache/commons/collections4/OrderedBidiMap.java new file mode 100644 index 0000000..1271c9e --- /dev/null +++ b/src/org/apache/commons/collections4/OrderedBidiMap.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a map that allows bidirectional lookup between key and values + * and retains and provides access to an ordering. + *

      + * Implementations should allow a value to be looked up from a key and + * a key to be looked up from a value with equal performance. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * + * @since 3.0 + * @version $Id: OrderedBidiMap.java 1543260 2013-11-19 00:47:22Z ggregory $ + */ +public interface OrderedBidiMap extends BidiMap, OrderedMap { + + /** + * Gets a view of this map where the keys and values are reversed. + *

      + * Changes to one map will be visible in the other and vice versa. + * This enables both directions of the map to be accessed equally. + *

      + * Implementations should seek to avoid creating a new object every time this + * method is called. See AbstractMap.values() etc. Calling this + * method on the inverse map should return the original. + *

      + * Implementations must return an OrderedBidiMap instance, + * usually by forwarding to inverseOrderedBidiMap(). + * + * @return an inverted bidirectional map + */ + OrderedBidiMap inverseBidiMap(); + +} diff --git a/src/org/apache/commons/collections4/OrderedIterator.java b/src/org/apache/commons/collections4/OrderedIterator.java new file mode 100644 index 0000000..095f494 --- /dev/null +++ b/src/org/apache/commons/collections4/OrderedIterator.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Iterator; + +/** + * Defines an iterator that operates over an ordered container. Subset of {@link java.util.ListIterator}. + *

      + * This iterator allows both forward and reverse iteration through the container. + * + * @param the type to iterate over + * @since 3.0 + * @version $Id: OrderedIterator.java 1469004 2013-04-17 17:37:03Z tn $ + */ +public interface OrderedIterator extends Iterator { + + /** + * Checks to see if there is a previous element that can be iterated to. + * + * @return true if the iterator has a previous element + */ + boolean hasPrevious(); + + /** + * Gets the previous element from the container. + * + * @return the previous element in the iteration + * @throws java.util.NoSuchElementException if the iteration is finished + */ + E previous(); + +} diff --git a/src/org/apache/commons/collections4/OrderedMap.java b/src/org/apache/commons/collections4/OrderedMap.java new file mode 100644 index 0000000..b582a99 --- /dev/null +++ b/src/org/apache/commons/collections4/OrderedMap.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a map that maintains order and allows both forward and backward + * iteration through that order. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * + * @since 3.0 + * @version $Id: OrderedMap.java 1543259 2013-11-19 00:47:07Z ggregory $ + */ +public interface OrderedMap extends IterableMap { + + /** + * Obtains an OrderedMapIterator over the map. + *

      + * A ordered map iterator is an efficient way of iterating over maps + * in both directions. + * + * @return a map iterator + */ + OrderedMapIterator mapIterator(); + + /** + * Gets the first key currently in this map. + * + * @return the first key currently in this map + * @throws java.util.NoSuchElementException if this map is empty + */ + K firstKey(); + + /** + * Gets the last key currently in this map. + * + * @return the last key currently in this map + * @throws java.util.NoSuchElementException if this map is empty + */ + K lastKey(); + + /** + * Gets the next key after the one specified. + * + * @param key the key to search for next from + * @return the next key, null if no match or at end + */ + K nextKey(K key); + + /** + * Gets the previous key before the one specified. + * + * @param key the key to search for previous from + * @return the previous key, null if no match or at start + */ + K previousKey(K key); + +} diff --git a/src/org/apache/commons/collections4/OrderedMapIterator.java b/src/org/apache/commons/collections4/OrderedMapIterator.java new file mode 100644 index 0000000..7e76ff2 --- /dev/null +++ b/src/org/apache/commons/collections4/OrderedMapIterator.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines an iterator that operates over an ordered Map. + *

      + * This iterator allows both forward and reverse iteration through the map. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * @since 3.0 + * @version $Id: OrderedMapIterator.java 1469004 2013-04-17 17:37:03Z tn $ + */ +public interface OrderedMapIterator extends MapIterator, OrderedIterator { + + /** + * Checks to see if there is a previous entry that can be iterated to. + * + * @return true if the iterator has a previous element + */ + boolean hasPrevious(); + + /** + * Gets the previous key from the Map. + * + * @return the previous key in the iteration + * @throws java.util.NoSuchElementException if the iteration is finished + */ + K previous(); + +} diff --git a/src/org/apache/commons/collections4/Predicate.java b/src/org/apache/commons/collections4/Predicate.java new file mode 100644 index 0000000..ce7df99 --- /dev/null +++ b/src/org/apache/commons/collections4/Predicate.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a functor interface implemented by classes that perform a predicate + * test on an object. + *

      + * A Predicate is the object equivalent of an if statement. + * It uses the input object to return a true or false value, and is often used in + * validation or filtering. + *

      + * Standard implementations of common predicates are provided by + * {@link PredicateUtils}. These include true, false, instanceof, equals, and, + * or, not, method invokation and null testing. + * + * @param the type that the predicate queries + * + * @since 1.0 + * @version $Id: Predicate.java 1543262 2013-11-19 00:47:45Z ggregory $ + */ +public interface Predicate { + + /** + * Use the specified parameter to perform a test that returns true or false. + * + * @param object the object to evaluate, should not be changed + * @return true or false + * @throws ClassCastException (runtime) if the input is the wrong class + * @throws IllegalArgumentException (runtime) if the input is invalid + * @throws FunctorException (runtime) if the predicate encounters a problem + */ + boolean evaluate(T object); + +} diff --git a/src/org/apache/commons/collections4/PredicateUtils.java b/src/org/apache/commons/collections4/PredicateUtils.java new file mode 100644 index 0000000..a5d0cea --- /dev/null +++ b/src/org/apache/commons/collections4/PredicateUtils.java @@ -0,0 +1,542 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; + +import org.apache.commons.collections4.functors.AllPredicate; +import org.apache.commons.collections4.functors.AndPredicate; +import org.apache.commons.collections4.functors.AnyPredicate; +import org.apache.commons.collections4.functors.EqualPredicate; +import org.apache.commons.collections4.functors.ExceptionPredicate; +import org.apache.commons.collections4.functors.FalsePredicate; +import org.apache.commons.collections4.functors.IdentityPredicate; +import org.apache.commons.collections4.functors.InstanceofPredicate; +import org.apache.commons.collections4.functors.InvokerTransformer; +import org.apache.commons.collections4.functors.NonePredicate; +import org.apache.commons.collections4.functors.NotNullPredicate; +import org.apache.commons.collections4.functors.NotPredicate; +import org.apache.commons.collections4.functors.NullIsExceptionPredicate; +import org.apache.commons.collections4.functors.NullIsFalsePredicate; +import org.apache.commons.collections4.functors.NullIsTruePredicate; +import org.apache.commons.collections4.functors.NullPredicate; +import org.apache.commons.collections4.functors.OnePredicate; +import org.apache.commons.collections4.functors.OrPredicate; +import org.apache.commons.collections4.functors.TransformedPredicate; +import org.apache.commons.collections4.functors.TransformerPredicate; +import org.apache.commons.collections4.functors.TruePredicate; +import org.apache.commons.collections4.functors.UniquePredicate; + +/** + * PredicateUtils provides reference implementations and utilities + * for the Predicate functor interface. The supplied predicates are: + *

        + *
      • Invoker - returns the result of a method call on the input object + *
      • InstanceOf - true if the object is an instanceof a class + *
      • Equal - true if the object equals() a specified object + *
      • Identity - true if the object == a specified object + *
      • Null - true if the object is null + *
      • NotNull - true if the object is not null + *
      • Unique - true if the object has not already been evaluated + *
      • And/All - true if all of the predicates are true + *
      • Or/Any - true if any of the predicates is true + *
      • Either/One - true if only one of the predicate is true + *
      • Neither/None - true if none of the predicates are true + *
      • Not - true if the predicate is false, and vice versa + *
      • Transformer - wraps a Transformer as a Predicate + *
      • True - always return true + *
      • False - always return false + *
      • Exception - always throws an exception + *
      • NullIsException/NullIsFalse/NullIsTrue - check for null input + *
      • Transformed - transforms the input before calling the predicate + *
      + * All the supplied predicates are Serializable. + * + * @since 3.0 + * @version $Id: PredicateUtils.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicateUtils { + + /** + * This class is not normally instantiated. + */ + private PredicateUtils() {} + + // Simple predicates + //----------------------------------------------------------------------------- + + /** + * Gets a Predicate that always throws an exception. + * This could be useful during testing as a placeholder. + * + * @param the type that the predicate queries + * @return the predicate + * @see ExceptionPredicate + */ + public static Predicate exceptionPredicate() { + return ExceptionPredicate.exceptionPredicate(); + } + + /** + * Gets a Predicate that always returns true. + * + * @param the type that the predicate queries + * @return the predicate + * @see TruePredicate + */ + public static Predicate truePredicate() { + return TruePredicate.truePredicate(); + } + + /** + * Gets a Predicate that always returns false. + * + * @param the type that the predicate queries + * @return the predicate + * @see FalsePredicate + */ + public static Predicate falsePredicate() { + return FalsePredicate.falsePredicate(); + } + + /** + * Gets a Predicate that checks if the input object passed in is null. + * + * @param the type that the predicate queries + * @return the predicate + * @see NullPredicate + */ + public static Predicate nullPredicate() { + return NullPredicate.nullPredicate(); + } + + /** + * Gets a Predicate that checks if the input object passed in is not null. + * + * @param the type that the predicate queries + * @return the predicate + * @see NotNullPredicate + */ + public static Predicate notNullPredicate() { + return NotNullPredicate.notNullPredicate(); + } + + /** + * Creates a Predicate that checks if the input object is equal to the + * specified object using equals(). + * + * @param the type that the predicate queries + * @param value the value to compare against + * @return the predicate + * @see EqualPredicate + */ + public static Predicate equalPredicate(final T value) { + return EqualPredicate.equalPredicate(value); + } + + /** + * Creates a Predicate that checks if the input object is equal to the + * specified object by identity. + * + * @param the type that the predicate queries + * @param value the value to compare against + * @return the predicate + * @see IdentityPredicate + */ + public static Predicate identityPredicate(final T value) { + return IdentityPredicate.identityPredicate(value); + } + + /** + * Creates a Predicate that checks if the object passed in is of + * a particular type, using instanceof. A null input + * object will return false. + * + * @param type the type to check for, may not be null + * @return the predicate + * @throws NullPointerException if the class is null + * @see InstanceofPredicate + */ + public static Predicate instanceofPredicate(final Class type) { + return InstanceofPredicate.instanceOfPredicate(type); + } + + /** + * Creates a Predicate that returns true the first time an object is + * encountered, and false if the same object is received + * again. The comparison is by equals(). A null input object + * is accepted and will return true the first time, and false subsequently + * as well. + * + * @param the type that the predicate queries + * @return the predicate + * @see UniquePredicate + */ + public static Predicate uniquePredicate() { + // must return new instance each time + return UniquePredicate.uniquePredicate(); + } + + /** + * Creates a Predicate that invokes a method on the input object. + * The method must return either a boolean or a non-null Boolean, + * and have no parameters. If the input object is null, a + * PredicateException is thrown. + *

      + * For example, PredicateUtils.invokerPredicate("isEmpty"); + * will call the isEmpty method on the input object to + * determine the predicate result. + * + * @param the type that the predicate queries + * @param methodName the method name to call on the input object, may not be null + * @return the predicate + * @throws NullPointerException if the methodName is null. + * @see InvokerTransformer + * @see TransformerPredicate + */ + public static Predicate invokerPredicate(final String methodName) { + // reuse transformer as it has caching - this is lazy really, should have inner class here + return asPredicate(InvokerTransformer.invokerTransformer(methodName)); + } + + /** + * Creates a Predicate that invokes a method on the input object. + * The method must return either a boolean or a non-null Boolean, + * and have no parameters. If the input object is null, a + * PredicateException is thrown. + *

      + * For example, PredicateUtils.invokerPredicate("isEmpty"); + * will call the isEmpty method on the input object to + * determine the predicate result. + * + * @param the type that the predicate queries + * @param methodName the method name to call on the input object, may not be null + * @param paramTypes the parameter types + * @param args the arguments + * @return the predicate + * @throws NullPointerException if the method name is null + * @throws IllegalArgumentException if the paramTypes and args don't match + * @see InvokerTransformer + * @see TransformerPredicate + */ + public static Predicate invokerPredicate(final String methodName, final Class[] paramTypes, + final Object[] args) { + // reuse transformer as it has caching - this is lazy really, should have inner class here + return asPredicate(InvokerTransformer.invokerTransformer(methodName, paramTypes, args)); + } + + // Boolean combinations + //----------------------------------------------------------------------------- + + /** + * Create a new Predicate that returns true only if both of the specified + * predicates are true. + * + * @param the type that the predicate queries + * @param predicate1 the first predicate, may not be null + * @param predicate2 the second predicate, may not be null + * @return the and predicate + * @throws NullPointerException if either predicate is null + * @see AndPredicate + */ + public static Predicate andPredicate(final Predicate predicate1, + final Predicate predicate2) { + return AndPredicate.andPredicate(predicate1, predicate2); + } + + /** + * Create a new Predicate that returns true only if all of the specified + * predicates are true. + * If the array of predicates is empty, then this predicate returns true. + * + * @param the type that the predicate queries + * @param predicates an array of predicates to check, may not be null + * @return the all predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + * @see AllPredicate + */ + @SafeVarargs + public static Predicate allPredicate(final Predicate... predicates) { + return AllPredicate.allPredicate(predicates); + } + + /** + * Create a new Predicate that returns true only if all of the specified + * predicates are true. The predicates are checked in iterator order. + * If the collection of predicates is empty, then this predicate returns true. + * + * @param the type that the predicate queries + * @param predicates a collection of predicates to check, may not be null + * @return the all predicate + * @throws NullPointerException if the predicates collection is null + * @throws NullPointerException if any predicate in the collection is null + * @see AllPredicate + */ + public static Predicate allPredicate(final Collection> predicates) { + return AllPredicate.allPredicate(predicates); + } + + /** + * Create a new Predicate that returns true if either of the specified + * predicates are true. + * + * @param the type that the predicate queries + * @param predicate1 the first predicate, may not be null + * @param predicate2 the second predicate, may not be null + * @return the or predicate + * @throws NullPointerException if either predicate is null + * @see OrPredicate + */ + public static Predicate orPredicate(final Predicate predicate1, + final Predicate predicate2) { + return OrPredicate.orPredicate(predicate1, predicate2); + } + + /** + * Create a new Predicate that returns true if any of the specified + * predicates are true. + * If the array of predicates is empty, then this predicate returns false. + * + * @param the type that the predicate queries + * @param predicates an array of predicates to check, may not be null + * @return the any predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + * @see AnyPredicate + */ + @SafeVarargs + public static Predicate anyPredicate(final Predicate... predicates) { + return AnyPredicate.anyPredicate(predicates); + } + + /** + * Create a new Predicate that returns true if any of the specified + * predicates are true. The predicates are checked in iterator order. + * If the collection of predicates is empty, then this predicate returns false. + * + * @param the type that the predicate queries + * @param predicates a collection of predicates to check, may not be null + * @return the any predicate + * @throws NullPointerException if the predicates collection is null + * @throws NullPointerException if any predicate in the collection is null + * @see AnyPredicate + */ + public static Predicate anyPredicate(final Collection> predicates) { + return AnyPredicate.anyPredicate(predicates); + } + + /** + * Create a new Predicate that returns true if one, but not both, of the + * specified predicates are true. XOR + * + * @param the type that the predicate queries + * @param predicate1 the first predicate, may not be null + * @param predicate2 the second predicate, may not be null + * @return the either predicate + * @throws NullPointerException if either predicate is null + * @see OnePredicate + */ + public static Predicate eitherPredicate(final Predicate predicate1, + final Predicate predicate2) { + final Predicate onePredicate = PredicateUtils.onePredicate(predicate1, predicate2); + return onePredicate; + } + + /** + * Create a new Predicate that returns true if only one of the specified + * predicates are true. + * If the array of predicates is empty, then this predicate returns false. + * + * @param the type that the predicate queries + * @param predicates an array of predicates to check, may not be null + * @return the one predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + * @see OnePredicate + */ + @SafeVarargs + public static Predicate onePredicate(final Predicate... predicates) { + return OnePredicate.onePredicate(predicates); + } + + /** + * Create a new Predicate that returns true if only one of the specified + * predicates are true. The predicates are checked in iterator order. + * If the collection of predicates is empty, then this predicate returns false. + * + * @param the type that the predicate queries + * @param predicates a collection of predicates to check, may not be null + * @return the one predicate + * @throws NullPointerException if the predicates collection is null + * @throws NullPointerException if any predicate in the collection is null + * @see OnePredicate + */ + public static Predicate onePredicate(final Collection> predicates) { + return OnePredicate.onePredicate(predicates); + } + + /** + * Create a new Predicate that returns true if neither of the specified + * predicates are true. + * + * @param the type that the predicate queries + * @param predicate1 the first predicate, may not be null + * @param predicate2 the second predicate, may not be null + * @return the neither predicate + * @throws NullPointerException if either predicate is null + * @see NonePredicate + */ + public static Predicate neitherPredicate(final Predicate predicate1, + final Predicate predicate2) { + final Predicate nonePredicate = PredicateUtils.nonePredicate(predicate1, predicate2); + return nonePredicate; + } + + /** + * Create a new Predicate that returns true if none of the specified + * predicates are true. + * If the array of predicates is empty, then this predicate returns true. + * + * @param the type that the predicate queries + * @param predicates an array of predicates to check, may not be null + * @return the none predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + * @see NonePredicate + */ + @SafeVarargs + public static Predicate nonePredicate(final Predicate... predicates) { + return NonePredicate.nonePredicate(predicates); + } + + /** + * Create a new Predicate that returns true if none of the specified + * predicates are true. The predicates are checked in iterator order. + * If the collection of predicates is empty, then this predicate returns true. + * + * @param the type that the predicate queries + * @param predicates a collection of predicates to check, may not be null + * @return the none predicate + * @throws NullPointerException if the predicates collection is null + * @throws NullPointerException if any predicate in the collection is null + * @see NonePredicate + */ + public static Predicate nonePredicate(final Collection> predicates) { + return NonePredicate.nonePredicate(predicates); + } + + /** + * Create a new Predicate that returns true if the specified predicate + * returns false and vice versa. + * + * @param the type that the predicate queries + * @param predicate the predicate to not + * @return the not predicate + * @throws NullPointerException if the predicate is null + * @see NotPredicate + */ + public static Predicate notPredicate(final Predicate predicate) { + return NotPredicate.notPredicate(predicate); + } + + // Adaptors + //----------------------------------------------------------------------------- + + /** + * Create a new Predicate that wraps a Transformer. The Transformer must + * return either Boolean.TRUE or Boolean.FALSE otherwise a PredicateException + * will be thrown. + * + * @param the type that the predicate queries + * @param transformer the transformer to wrap, may not be null + * @return the transformer wrapping predicate + * @throws NullPointerException if the transformer is null + * @see TransformerPredicate + */ + public static Predicate asPredicate(final Transformer transformer) { + return TransformerPredicate.transformerPredicate(transformer); + } + + // Null handlers + //----------------------------------------------------------------------------- + + /** + * Gets a Predicate that throws an exception if the input object is null, + * otherwise it calls the specified Predicate. This allows null handling + * behaviour to be added to Predicates that don't support nulls. + * + * @param the type that the predicate queries + * @param predicate the predicate to wrap, may not be null + * @return the predicate + * @throws NullPointerException if the predicate is null. + * @see NullIsExceptionPredicate + */ + public static Predicate nullIsExceptionPredicate(final Predicate predicate){ + return NullIsExceptionPredicate.nullIsExceptionPredicate(predicate); + } + + /** + * Gets a Predicate that returns false if the input object is null, otherwise + * it calls the specified Predicate. This allows null handling behaviour to + * be added to Predicates that don't support nulls. + * + * @param the type that the predicate queries + * @param predicate the predicate to wrap, may not be null + * @return the predicate + * @throws NullPointerException if the predicate is null. + * @see NullIsFalsePredicate + */ + public static Predicate nullIsFalsePredicate(final Predicate predicate){ + return NullIsFalsePredicate.nullIsFalsePredicate(predicate); + } + + /** + * Gets a Predicate that returns true if the input object is null, otherwise + * it calls the specified Predicate. This allows null handling behaviour to + * be added to Predicates that don't support nulls. + * + * @param the type that the predicate queries + * @param predicate the predicate to wrap, may not be null + * @return the predicate + * @throws NullPointerException if the predicate is null. + * @see NullIsTruePredicate + */ + public static Predicate nullIsTruePredicate(final Predicate predicate){ + return NullIsTruePredicate.nullIsTruePredicate(predicate); + } + + // Transformed + //----------------------------------------------------------------------- + /** + * Creates a predicate that transforms the input object before passing it + * to the predicate. + * + * @param the type that the predicate queries + * @param transformer the transformer to call first + * @param predicate the predicate to call with the result of the transform + * @return the predicate + * @throws NullPointerException if the transformer or the predicate is null + * @see TransformedPredicate + * @since 3.1 + */ + public static Predicate transformedPredicate( + final Transformer transformer, final Predicate predicate) { + return TransformedPredicate.transformedPredicate(transformer, predicate); + } + +} diff --git a/src/org/apache/commons/collections4/Put.java b/src/org/apache/commons/collections4/Put.java new file mode 100644 index 0000000..7fe3165 --- /dev/null +++ b/src/org/apache/commons/collections4/Put.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Map; + +/** + * The "write" subset of the {@link Map} interface. + *

      + * NOTE: in the original {@link Map} interface, {@link Map#put(Object, Object)} is known + * to have the same return type as {@link Map#get(Object)}, namely {@code V}. {@link Put} + * makes no assumptions in this regard (there is no association with, nor even knowledge + * of, a "reading" interface) and thus defines {@link #put(Object, Object)} as returning + * {@link Object}. + * + * @since 4.0 + * @version $Id: Put.java 1543257 2013-11-19 00:45:55Z ggregory $ + * + * @see Get + */ +public interface Put { + + /** + * @see Map#clear() + */ + void clear(); + + /** + * Note that the return type is Object, rather than V as in the Map interface. + * See the class Javadoc for further info. + * + * @see Map#put(Object, Object) + */ + Object put(K key, V value); + + /** + * @see Map#putAll(Map) + */ + void putAll(Map t); + +} diff --git a/src/org/apache/commons/collections4/QueueUtils.java b/src/org/apache/commons/collections4/QueueUtils.java new file mode 100644 index 0000000..04d3191 --- /dev/null +++ b/src/org/apache/commons/collections4/QueueUtils.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.LinkedList; +import java.util.Queue; + +import org.apache.commons.collections4.queue.PredicatedQueue; +import org.apache.commons.collections4.queue.TransformedQueue; +import org.apache.commons.collections4.queue.UnmodifiableQueue; + +/** + * Provides utility methods and decorators for {@link Queue} instances. + * + * @since 4.0 + * @version $Id: QueueUtils.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class QueueUtils { + + /** + * An empty unmodifiable queue. + */ + @SuppressWarnings("rawtypes") // OK, empty queue is compatible with any type + public static final Queue EMPTY_QUEUE = UnmodifiableQueue.unmodifiableQueue(new LinkedList()); + + /** + * QueueUtils should not normally be instantiated. + */ + private QueueUtils() {} + + //----------------------------------------------------------------------- + + /** + * Returns an unmodifiable queue backed by the given queue. + * + * @param the type of the elements in the queue + * @param queue the queue to make unmodifiable, must not be null + * @return an unmodifiable queue backed by that queue + * @throws NullPointerException if the queue is null + */ + public static Queue unmodifiableQueue(final Queue queue) { + return UnmodifiableQueue.unmodifiableQueue(queue); + } + + /** + * Returns a predicated (validating) queue backed by the given queue. + *

      + * Only objects that pass the test in the given predicate can be added to the queue. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original queue after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the type of the elements in the queue + * @param queue the queue to predicate, must not be null + * @param predicate the predicate used to evaluate new elements, must not be null + * @return a predicated queue + * @throws NullPointerException if the queue or predicate is null + */ + public static Queue predicatedQueue(final Queue queue, final Predicate predicate) { + return PredicatedQueue.predicatedQueue(queue, predicate); + } + + /** + * Returns a transformed queue backed by the given queue. + *

      + * Each object is passed through the transformer as it is added to the + * Queue. It is important not to use the original queue after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

      + * Existing entries in the specified queue will not be transformed. + * If you want that behaviour, see {@link TransformedQueue#transformedQueue}. + * + * @param the type of the elements in the queue + * @param queue the queue to predicate, must not be null + * @param transformer the transformer for the queue, must not be null + * @return a transformed queue backed by the given queue + * @throws NullPointerException if the queue or transformer is null + */ + public static Queue transformingQueue(final Queue queue, + final Transformer transformer) { + return TransformedQueue.transformingQueue(queue, transformer); + } + + /** + * Get an empty Queue. + * + * @param the type of the elements in the queue + * @return an empty {@link Queue} + */ + @SuppressWarnings("unchecked") // OK, empty queue is compatible with any type + public static Queue emptyQueue() { + return (Queue) EMPTY_QUEUE; + } +} diff --git a/src/org/apache/commons/collections4/ResettableIterator.java b/src/org/apache/commons/collections4/ResettableIterator.java new file mode 100644 index 0000000..b3f8105 --- /dev/null +++ b/src/org/apache/commons/collections4/ResettableIterator.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Iterator; + +/** + * Defines an iterator that can be reset back to an initial state. + *

      + * This interface allows an iterator to be repeatedly reused. + * + * @param the type to iterate over + * @since 3.0 + * @version $Id: ResettableIterator.java 1543263 2013-11-19 00:47:55Z ggregory $ + */ +public interface ResettableIterator extends Iterator { + + /** + * Resets the iterator back to the position at which the iterator + * was created. + */ + void reset(); + +} diff --git a/src/org/apache/commons/collections4/ResettableListIterator.java b/src/org/apache/commons/collections4/ResettableListIterator.java new file mode 100644 index 0000000..5fcac2d --- /dev/null +++ b/src/org/apache/commons/collections4/ResettableListIterator.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.ListIterator; + +/** + * Defines a list iterator that can be reset back to an initial state. + *

      + * This interface allows an iterator to be repeatedly reused. + * + * @param the type to iterate over + * @since 3.0 + * @version $Id: ResettableListIterator.java 1477779 2013-04-30 18:55:24Z tn $ + */ +public interface ResettableListIterator extends ListIterator, ResettableIterator, OrderedIterator { + +} diff --git a/src/org/apache/commons/collections4/SetUtils.java b/src/org/apache/commons/collections4/SetUtils.java new file mode 100644 index 0000000..b110fb0 --- /dev/null +++ b/src/org/apache/commons/collections4/SetUtils.java @@ -0,0 +1,645 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.apache.commons.collections4.set.ListOrderedSet; +import org.apache.commons.collections4.set.PredicatedNavigableSet; +import org.apache.commons.collections4.set.PredicatedSet; +import org.apache.commons.collections4.set.PredicatedSortedSet; +import org.apache.commons.collections4.set.TransformedNavigableSet; +import org.apache.commons.collections4.set.TransformedSet; +import org.apache.commons.collections4.set.TransformedSortedSet; +import org.apache.commons.collections4.set.UnmodifiableNavigableSet; +import org.apache.commons.collections4.set.UnmodifiableSet; +import org.apache.commons.collections4.set.UnmodifiableSortedSet; + +/** + * Provides utility methods and decorators for + * {@link Set} and {@link SortedSet} instances. + * + * @since 2.1 + * @version $Id: SetUtils.java 1686950 2015-06-22 21:51:07Z tn $ + */ +public class SetUtils { + + /** + * Get a typed empty unmodifiable Set. + * @param the element type + * @return an empty Set + */ + public static Set emptySet() { + return Collections.emptySet(); + } + + /** + * An empty unmodifiable sorted set. + * This is not provided in the JDK. + */ + @SuppressWarnings("rawtypes") + public static final SortedSet EMPTY_SORTED_SET = + UnmodifiableSortedSet.unmodifiableSortedSet(new TreeSet()); + + /** + * Get a typed empty unmodifiable sorted set. + * @param the element type + * @return an empty sorted Set + */ + @SuppressWarnings("unchecked") // empty set is OK for any type + public static SortedSet emptySortedSet() { + return EMPTY_SORTED_SET; + } + + /** + * SetUtils should not normally be instantiated. + */ + private SetUtils() {} + + //----------------------------------------------------------------------- + + /** + * Returns an immutable empty set if the argument is null, + * or the argument itself otherwise. + * + * @param the element type + * @param set the set, possibly null + * @return an empty set if the argument is null + */ + public static Set emptyIfNull(final Set set) { + return set == null ? Collections.emptySet() : set; + } + + /** + * Tests two sets for equality as per the equals() contract + * in {@link java.util.Set#equals(java.lang.Object)}. + *

      + * This method is useful for implementing Set when you cannot + * extend AbstractSet. The method takes Collection instances to enable other + * collection types to use the Set implementation algorithm. + *

      + * The relevant text (slightly paraphrased as this is a static method) is: + *

      + *

      Two sets are considered equal if they have + * the same size, and every member of the first set is contained in + * the second. This ensures that the {@code equals} method works + * properly across different implementations of the {@code Set} + * interface.

      + * + *

      + * This implementation first checks if the two sets are the same object: + * if so it returns {@code true}. Then, it checks if the two sets are + * identical in size; if not, it returns false. If so, it returns + * {@code a.containsAll((Collection) b)}.

      + *
      + * + * @see java.util.Set + * @param set1 the first set, may be null + * @param set2 the second set, may be null + * @return whether the sets are equal by value comparison + */ + public static boolean isEqualSet(final Collection set1, final Collection set2) { + if (set1 == set2) { + return true; + } + if (set1 == null || set2 == null || set1.size() != set2.size()) { + return false; + } + + return set1.containsAll(set2); + } + + /** + * Generates a hash code using the algorithm specified in + * {@link java.util.Set#hashCode()}. + *

      + * This method is useful for implementing Set when you cannot + * extend AbstractSet. The method takes Collection instances to enable other + * collection types to use the Set implementation algorithm. + * + * @param the element type + * @see java.util.Set#hashCode() + * @param set the set to calculate the hash code for, may be null + * @return the hash code + */ + public static int hashCodeForSet(final Collection set) { + if (set == null) { + return 0; + } + + int hashCode = 0; + for (final T obj : set) { + if (obj != null) { + hashCode += obj.hashCode(); + } + } + return hashCode; + } + + /** + * Returns a new hash set that matches elements based on == not + * equals(). + *

      + * This set will violate the detail of various Set contracts. + * As a general rule, don't compare this set to other sets. In particular, you can't + * use decorators like {@link ListOrderedSet} on it, which silently assume that these + * contracts are fulfilled. + *

      + * Note that the returned set is not synchronized and is not thread-safe. + * If you wish to use this set from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedSet(Set)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @param the element type + * @return a new identity hash set + * @since 4.1 + */ + public static Set newIdentityHashSet() { + return Collections.newSetFromMap(new IdentityHashMap()); + } + + // Set + //----------------------------------------------------------------------- + /** + * Returns a synchronized set backed by the given set. + *

      + * You must manually synchronize on the returned set's iterator to + * avoid non-deterministic behavior: + * + *

      +     * Set s = SetUtils.synchronizedSet(mySet);
      +     * synchronized (s) {
      +     *     Iterator i = s.iterator();
      +     *     while (i.hasNext()) {
      +     *         process (i.next());
      +     *     }
      +     * }
      +     * 
      + * + * This method is just a wrapper for {@link Collections#synchronizedSet(Set)}. + * + * @param the element type + * @param set the set to synchronize, must not be null + * @return a synchronized set backed by the given set + * @throws NullPointerException if the set is null + */ + public static Set synchronizedSet(final Set set) { + return Collections.synchronizedSet(set); + } + + /** + * Returns an unmodifiable set backed by the given set. + *

      + * This method uses the implementation in the decorators subpackage. + * + * @param the element type + * @param set the set to make unmodifiable, must not be null + * @return an unmodifiable set backed by the given set + * @throws NullPointerException if the set is null + */ + public static Set unmodifiableSet(final Set set) { + return UnmodifiableSet.unmodifiableSet(set); + } + + /** + * Returns a predicated (validating) set backed by the given set. + *

      + * Only objects that pass the test in the given predicate can be added to the set. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original set after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the element type + * @param set the set to predicate, must not be null + * @param predicate the predicate for the set, must not be null + * @return a predicated set backed by the given set + * @throws NullPointerException if the set or predicate is null + */ + public static Set predicatedSet(final Set set, final Predicate predicate) { + return PredicatedSet.predicatedSet(set, predicate); + } + + /** + * Returns a transformed set backed by the given set. + *

      + * Each object is passed through the transformer as it is added to the + * Set. It is important not to use the original set after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

      + * Existing entries in the specified set will not be transformed. + * If you want that behaviour, see {@link TransformedSet#transformedSet}. + * + * @param the element type + * @param set the set to transform, must not be null + * @param transformer the transformer for the set, must not be null + * @return a transformed set backed by the given set + * @throws NullPointerException if the set or transformer is null + */ + public static Set transformedSet(final Set set, + final Transformer transformer) { + return TransformedSet.transformingSet(set, transformer); + } + + /** + * Returns a set that maintains the order of elements that are added + * backed by the given set. + *

      + * If an element is added twice, the order is determined by the first add. + * The order is observed through the iterator or toArray. + * + * @param the element type + * @param set the set to order, must not be null + * @return an ordered set backed by the given set + * @throws NullPointerException if the set is null + */ + public static Set orderedSet(final Set set) { + return ListOrderedSet.listOrderedSet(set); + } + + // SortedSet + //----------------------------------------------------------------------- + /** + * Returns a synchronized sorted set backed by the given sorted set. + *

      + * You must manually synchronize on the returned set's iterator to + * avoid non-deterministic behavior: + * + *

      +     * Set s = SetUtils.synchronizedSortedSet(mySet);
      +     * synchronized (s) {
      +     *     Iterator i = s.iterator();
      +     *     while (i.hasNext()) {
      +     *         process (i.next());
      +     *     }
      +     * }
      +     * 
      + * + * This method is just a wrapper for {@link Collections#synchronizedSortedSet(SortedSet)}. + * + * @param the element type + * @param set the sorted set to synchronize, must not be null + * @return a synchronized set backed by the given set + * @throws NullPointerException if the set is null + */ + public static SortedSet synchronizedSortedSet(final SortedSet set) { + return Collections.synchronizedSortedSet(set); + } + + /** + * Returns an unmodifiable sorted set backed by the given sorted set. + *

      + * This method uses the implementation in the decorators subpackage. + * + * @param the element type + * @param set the sorted set to make unmodifiable, must not be null + * @return an unmodifiable set backed by the given set + * @throws NullPointerException if the set is null + */ + public static SortedSet unmodifiableSortedSet(final SortedSet set) { + return UnmodifiableSortedSet.unmodifiableSortedSet(set); + } + + /** + * Returns a predicated (validating) sorted set backed by the given sorted set. + *

      + * Only objects that pass the test in the given predicate can be added to the set. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original set after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the element type + * @param set the sorted set to predicate, must not be null + * @param predicate the predicate for the sorted set, must not be null + * @return a predicated sorted set backed by the given sorted set + * @throws NullPointerException if the set or predicate is null + */ + public static SortedSet predicatedSortedSet(final SortedSet set, + final Predicate predicate) { + return PredicatedSortedSet.predicatedSortedSet(set, predicate); + } + + /** + * Returns a transformed sorted set backed by the given set. + *

      + * Each object is passed through the transformer as it is added to the + * Set. It is important not to use the original set after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

      + * Existing entries in the specified set will not be transformed. + * If you want that behaviour, see {@link TransformedSortedSet#transformedSortedSet}. + * + * @param the element type + * @param set the set to transform, must not be null + * @param transformer the transformer for the set, must not be null + * @return a transformed set backed by the given set + * @throws NullPointerException if the set or transformer is null + */ + public static SortedSet transformedSortedSet(final SortedSet set, + final Transformer transformer) { + return TransformedSortedSet.transformingSortedSet(set, transformer); + } + + // NavigableSet + //----------------------------------------------------------------------- + /** + * Returns an unmodifiable navigable set backed by the given navigable set. + *

      + * This method uses the implementation in the decorators subpackage. + * + * @param the element type + * @param set the navigable set to make unmodifiable, must not be null + * @return an unmodifiable set backed by the given set + * @throws NullPointerException if the set is null + * @since 4.1 + */ + public static SortedSet unmodifiableNavigableSet(final NavigableSet set) { + return UnmodifiableNavigableSet.unmodifiableNavigableSet(set); + } + + /** + * Returns a predicated (validating) navigable set backed by the given navigable set. + *

      + * Only objects that pass the test in the given predicate can be added to the set. + * Trying to add an invalid object results in an IllegalArgumentException. + * It is important not to use the original set after invoking this method, + * as it is a backdoor for adding invalid objects. + * + * @param the element type + * @param set the navigable set to predicate, must not be null + * @param predicate the predicate for the navigable set, must not be null + * @return a predicated navigable set backed by the given navigable set + * @throws NullPointerException if the set or predicate is null + * @since 4.1 + */ + public static SortedSet predicatedNavigableSet(final NavigableSet set, + final Predicate predicate) { + return PredicatedNavigableSet.predicatedNavigableSet(set, predicate); + } + + /** + * Returns a transformed navigable set backed by the given navigable set. + *

      + * Each object is passed through the transformer as it is added to the + * Set. It is important not to use the original set after invoking this + * method, as it is a backdoor for adding untransformed objects. + *

      + * Existing entries in the specified set will not be transformed. + * If you want that behaviour, see {@link TransformedNavigableSet#transformedNavigableSet}. + * + * @param the element type + * @param set the navigable set to transform, must not be null + * @param transformer the transformer for the set, must not be null + * @return a transformed set backed by the given set + * @throws NullPointerException if the set or transformer is null + * @since 4.1 + */ + public static SortedSet transformedNavigableSet(final NavigableSet set, + final Transformer transformer) { + return TransformedNavigableSet.transformingNavigableSet(set, transformer); + } + + // Set operations + //----------------------------------------------------------------------- + + /** + * Returns a unmodifiable view of the union of the given {@link Set}s. + *

      + * The returned view contains all elements of {@code a} and {@code b}. + * + * @param the generic type that is able to represent the types contained + * in both input sets. + * @param a the first set, must not be null + * @param b the second set, must not be null + * @return a view of the union of the two set + * @throws NullPointerException if either input set is null + * @since 4.1 + */ + public static SetView union(final Set a, final Set b) { + if (a == null || b == null) { + throw new NullPointerException("Sets must not be null."); + } + + final SetView bMinusA = difference(b, a); + + return new SetView() { + @Override + public boolean contains(Object o) { + return a.contains(o) || b.contains(o); + } + + @Override + public Iterator createIterator() { + return IteratorUtils.chainedIterator(a.iterator(), bMinusA.iterator()); + } + + @Override + public boolean isEmpty() { + return a.isEmpty() && b.isEmpty(); + } + + @Override + public int size() { + return a.size() + bMinusA.size(); + } + }; + } + + /** + * Returns a unmodifiable view containing the difference of the given + * {@link Set}s, denoted by {@code a \ b} (or {@code a - b}). + *

      + * The returned view contains all elements of {@code a} that are not a member + * of {@code b}. + * + * @param the generic type that is able to represent the types contained + * in both input sets. + * @param a the set to subtract from, must not be null + * @param b the set to subtract, must not be null + * @return a view of the relative complement of of the two sets + * @since 4.1 + */ + public static SetView difference(final Set a, final Set b) { + if (a == null || b == null) { + throw new NullPointerException("Sets must not be null."); + } + + final Predicate notContainedInB = new Predicate() { + @Override + public boolean evaluate(E object) { + return !b.contains(object); + } + }; + + return new SetView() { + @Override + public boolean contains(Object o) { + return a.contains(o) && !b.contains(o); + } + + @Override + public Iterator createIterator() { + return IteratorUtils.filteredIterator(a.iterator(), notContainedInB); + } + }; + } + + /** + * Returns a unmodifiable view of the intersection of the given {@link Set}s. + *

      + * The returned view contains all elements that are members of both input sets + * ({@code a} and {@code b}). + * + * @param the generic type that is able to represent the types contained + * in both input sets. + * @param a the first set, must not be null + * @param b the second set, must not be null + * @return a view of the intersection of the two sets + * @since 4.1 + */ + public static SetView intersection(final Set a, final Set b) { + if (a == null || b == null) { + throw new NullPointerException("Sets must not be null."); + } + + final Predicate containedInB = new Predicate() { + @Override + public boolean evaluate(E object) { + return b.contains(object); + } + }; + + return new SetView() { + @Override + public boolean contains(Object o) { + return a.contains(o) && b.contains(o); + } + + @Override + public Iterator createIterator() { + return IteratorUtils.filteredIterator(a.iterator(), containedInB); + } + }; + } + + /** + * Returns a unmodifiable view of the symmetric difference of the given + * {@link Set}s. + *

      + * The returned view contains all elements of {@code a} and {@code b} that are + * not a member of the other set. + *

      + * This is equivalent to {@code union(difference(a, b), difference(b, a))}. + * + * @param the generic type that is able to represent the types contained + * in both input sets. + * @param a the first set, must not be null + * @param b the second set, must not be null + * @return a view of the symmetric difference of the two sets + * @since 4.1 + */ + public static SetView disjunction(final Set a, final Set b) { + if (a == null || b == null) { + throw new NullPointerException("Sets must not be null."); + } + + final SetView aMinusB = difference(a, b); + final SetView bMinusA = difference(b, a); + + return new SetView() { + @Override + public boolean contains(Object o) { + return a.contains(o) ^ b.contains(o); + } + + @Override + public Iterator createIterator() { + return IteratorUtils.chainedIterator(aMinusB.iterator(), bMinusA.iterator()); + } + + @Override + public boolean isEmpty() { + return aMinusB.isEmpty() && bMinusA.isEmpty(); + } + + @Override + public int size() { + return aMinusB.size() + bMinusA.size(); + } + }; + } + + /** + * An unmodifiable view of a set that may be backed by other sets. + *

      + * If the decorated sets change, this view will change as well. The contents + * of this view can be transferred to another instance via the {@link #copyInto(Set)} + * and {@link #toSet()} methods. + * + * @param the element type + * @since 4.1 + */ + public static abstract class SetView extends AbstractSet { + + @Override + public Iterator iterator() { + return IteratorUtils.unmodifiableIterator(createIterator()); + } + + /** + * Return an iterator for this view; the returned iterator is + * not required to be unmodifiable. + * @return a new iterator for this view + */ + protected abstract Iterator createIterator(); + + @Override + public int size() { + return IteratorUtils.size(iterator()); + } + + /** + * Copies the contents of this view into the provided set. + * + * @param the set type + * @param set the set for copying the contents + */ + public > void copyInto(final S set) { + CollectionUtils.addAll(set, this); + } + + /** + * Returns a new set containing the contents of this view. + * + * @return a new set containing all elements of this view + */ + public Set toSet() { + final Set set = new HashSet(size()); + copyInto(set); + return set; + } + } +} diff --git a/src/org/apache/commons/collections4/SetValuedMap.java b/src/org/apache/commons/collections4/SetValuedMap.java new file mode 100644 index 0000000..faf1017 --- /dev/null +++ b/src/org/apache/commons/collections4/SetValuedMap.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Set; + +/** + * Defines a map that holds a set of values against each key. + *

      + * A {@code SetValuedMap} is a Map with slightly different semantics: + *

        + *
      • Putting a value into the map will add the value to a {@link Set} at that key.
      • + *
      • Getting a value will return a {@link Set}, holding all the values put to that key.
      • + *
      + * + * @since 4.1 + * @version $Id: SetValuedMap.java 1685299 2015-06-13 18:27:11Z tn $ + */ +public interface SetValuedMap extends MultiValuedMap { + + /** + * Gets the set of values associated with the specified key. + *

      + * Implementations typically return an empty {@code Set} if no values + * have been mapped to the key. + *

      + * + * @param key the key to retrieve + * @return the {@code Set} of values, implementations should return an + * empty {@code Set} for no mapping + * @throws NullPointerException if the key is null and null keys are invalid + */ + @Override + Set get(K key); + + /** + * Removes all values associated with the specified key. + *

      + * The returned set may be modifiable, but updates will not be + * propagated to this set-valued map. In case no mapping was stored for the + * specified key, an empty, unmodifiable set will be returned. + * + * @param key the key to remove values from + * @return the {@code Set} of values removed, implementations should + * return null for no mapping found, but may return an empty collection + * @throws UnsupportedOperationException if the map is unmodifiable + * @throws NullPointerException if the key is null and null keys are invalid + */ + @Override + Set remove(Object key); +} diff --git a/src/org/apache/commons/collections4/SortedBag.java b/src/org/apache/commons/collections4/SortedBag.java new file mode 100644 index 0000000..b38a27d --- /dev/null +++ b/src/org/apache/commons/collections4/SortedBag.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Comparator; + +/** + * Defines a type of Bag that maintains a sorted order among + * its unique representative members. + * + * @param the type to iterate over + * @since 2.0 + * @version $Id: SortedBag.java 1543264 2013-11-19 00:48:12Z ggregory $ + */ +public interface SortedBag extends Bag { + + /** + * Returns the comparator associated with this sorted set, or null + * if it uses its elements' natural ordering. + * + * @return the comparator in use, or null if natural ordering + */ + Comparator comparator(); + + /** + * Returns the first (lowest) member. + * + * @return the first element in the sorted bag + */ + E first(); + + /** + * Returns the last (highest) member. + * + * @return the last element in the sorted bag + */ + E last(); + +} diff --git a/src/org/apache/commons/collections4/SortedBidiMap.java b/src/org/apache/commons/collections4/SortedBidiMap.java new file mode 100644 index 0000000..115692f --- /dev/null +++ b/src/org/apache/commons/collections4/SortedBidiMap.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Comparator; +import java.util.SortedMap; + +/** + * Defines a map that allows bidirectional lookup between key and values + * and retains both keys and values in sorted order. + *

      + * Implementations should allow a value to be looked up from a key and + * a key to be looked up from a value with equal performance. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * @since 3.0 + * @version $Id: SortedBidiMap.java 1543255 2013-11-19 00:45:24Z ggregory $ + */ +public interface SortedBidiMap extends OrderedBidiMap, SortedMap { + + /** + * Gets a view of this map where the keys and values are reversed. + *

      + * Changes to one map will be visible in the other and vice versa. + * This enables both directions of the map to be accessed equally. + *

      + * Implementations should seek to avoid creating a new object every time this + * method is called. See AbstractMap.values() etc. Calling this + * method on the inverse map should return the original. + *

      + * Implementations must return a SortedBidiMap instance, + * usually by forwarding to inverseSortedBidiMap(). + * + * @return an inverted bidirectional map + */ + SortedBidiMap inverseBidiMap(); + + /** + * Get the comparator used for the values in the value-to-key map aspect. + * @return Comparator + */ + Comparator valueComparator(); +} diff --git a/src/org/apache/commons/collections4/SplitMapUtils.java b/src/org/apache/commons/collections4/SplitMapUtils.java new file mode 100644 index 0000000..49830d4 --- /dev/null +++ b/src/org/apache/commons/collections4/SplitMapUtils.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; +import org.apache.commons.collections4.map.EntrySetToMapIteratorAdapter; +import org.apache.commons.collections4.map.UnmodifiableEntrySet; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Utilities for working with "split maps:" objects that implement {@link Put} + * and/or {@link Get} but not {@link Map}. + * + * @since 4.0 + * @version $Id: SplitMapUtils.java 1686855 2015-06-22 13:00:27Z tn $ + * + * @see Get + * @see Put + */ +public class SplitMapUtils { + + /** + * SplitMapUtils should not normally be instantiated. + */ + private SplitMapUtils() {} + + //----------------------------------------------------------------------- + + private static class WrappedGet implements IterableMap, Unmodifiable { + private final Get get; + + private WrappedGet(final Get get) { + this.get = get; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public boolean containsKey(final Object key) { + return get.containsKey(key); + } + + public boolean containsValue(final Object value) { + return get.containsValue(value); + } + + public Set> entrySet() { + return UnmodifiableEntrySet.unmodifiableEntrySet(get.entrySet()); + } + + @Override + public boolean equals(final Object arg0) { + if (arg0 == this) { + return true; + } + return arg0 instanceof WrappedGet && ((WrappedGet) arg0).get.equals(this.get); + } + + public V get(final Object key) { + return get.get(key); + } + + @Override + public int hashCode() { + return ("WrappedGet".hashCode() << 4) | get.hashCode(); + } + + public boolean isEmpty() { + return get.isEmpty(); + } + + public Set keySet() { + return UnmodifiableSet.unmodifiableSet(get.keySet()); + } + + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + public void putAll(final Map t) { + throw new UnsupportedOperationException(); + } + + public V remove(final Object key) { + return get.remove(key); + } + + public int size() { + return get.size(); + } + + public Collection values() { + return UnmodifiableCollection.unmodifiableCollection(get.values()); + } + + public MapIterator mapIterator() { + MapIterator it; + if (get instanceof IterableGet) { + it = ((IterableGet) get).mapIterator(); + } else { + it = new EntrySetToMapIteratorAdapter(get.entrySet()); + } + return UnmodifiableMapIterator.unmodifiableMapIterator(it); + } + } + + private static class WrappedPut implements Map, Put { + private final Put put; + + private WrappedPut(final Put put) { + this.put = put; + } + + public void clear() { + put.clear(); + } + + public boolean containsKey(final Object key) { + throw new UnsupportedOperationException(); + } + + public boolean containsValue(final Object value) { + throw new UnsupportedOperationException(); + } + + public Set> entrySet() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + return obj instanceof WrappedPut && ((WrappedPut) obj).put.equals(this.put); + } + + public V get(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + return ("WrappedPut".hashCode() << 4) | put.hashCode(); + } + + public boolean isEmpty() { + throw new UnsupportedOperationException(); + } + + public Set keySet() { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public V put(final K key, final V value) { + return (V) put.put(key, value); + } + + public void putAll(final Map t) { + put.putAll(t); + } + + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + public int size() { + throw new UnsupportedOperationException(); + } + + public Collection values() { + throw new UnsupportedOperationException(); + } + } + + //----------------------------------------------------------------------- + + /** + * Get the specified {@link Get} as an instance of {@link IterableMap}. + * If get implements {@link IterableMap} directly, no conversion will take place. + * If get implements {@link Map} but not {@link IterableMap} it will be decorated. + * Otherwise an {@link Unmodifiable} {@link IterableMap} will be returned. + * @param the key type + * @param the value type + * @param get to wrap, must not be null + * @return {@link IterableMap} + * @throws NullPointerException if the argument is null + */ + @SuppressWarnings("unchecked") + public static IterableMap readableMap(final Get get) { + if (get == null) { + throw new NullPointerException("Get must not be null"); + } + if (get instanceof Map) { + return get instanceof IterableMap ? + ((IterableMap) get) : + MapUtils.iterableMap((Map) get); + } + return new WrappedGet(get); + } + + /** + * Get the specified {@link Put} as an instanceof {@link Map}. + * If put implements {@link Map} directly, no conversion will take place. + * Otherwise a write-only {@link Map} will be returned. On such a {@link Map} + * it is recommended that the result of #put(K, V) be discarded as it likely will not + * match V at runtime. + * + * @param the key type + * @param the element type + * @param put to wrap, must not be null + * @return {@link Map} + * @throws NullPointerException if the argument is null + */ + @SuppressWarnings("unchecked") + public static Map writableMap(final Put put) { + if (put == null) { + throw new NullPointerException("Put must not be null"); + } + if (put instanceof Map) { + return (Map) put; + } + return new WrappedPut(put); + } + +} diff --git a/src/org/apache/commons/collections4/Transformer.java b/src/org/apache/commons/collections4/Transformer.java new file mode 100644 index 0000000..138f647 --- /dev/null +++ b/src/org/apache/commons/collections4/Transformer.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Defines a functor interface implemented by classes that transform one + * object into another. + *

      + * A Transformer converts the input object to the output object. + * The input object should be left unchanged. + * Transformers are typically used for type conversions, or extracting data + * from an object. + *

      + * Standard implementations of common transformers are provided by + * {@link TransformerUtils}. These include method invocation, returning a constant, + * cloning and returning the string value. + * + * @param the input type to the transformer + * @param the output type from the transformer + * + * @since 1.0 + * @version $Id: Transformer.java 1543278 2013-11-19 00:54:07Z ggregory $ + */ +public interface Transformer { + + /** + * Transforms the input object (leaving it unchanged) into some output object. + * + * @param input the object to be transformed, should be left unchanged + * @return a transformed object + * @throws ClassCastException (runtime) if the input is the wrong class + * @throws IllegalArgumentException (runtime) if the input is invalid + * @throws FunctorException (runtime) if the transform cannot be completed + */ + O transform(I input); + +} diff --git a/src/org/apache/commons/collections4/TransformerUtils.java b/src/org/apache/commons/collections4/TransformerUtils.java new file mode 100644 index 0000000..fac3984 --- /dev/null +++ b/src/org/apache/commons/collections4/TransformerUtils.java @@ -0,0 +1,485 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.Collection; +import java.util.Map; + +import org.apache.commons.collections4.functors.ChainedTransformer; +import org.apache.commons.collections4.functors.CloneTransformer; +import org.apache.commons.collections4.functors.ClosureTransformer; +import org.apache.commons.collections4.functors.ConstantTransformer; +import org.apache.commons.collections4.functors.EqualPredicate; +import org.apache.commons.collections4.functors.ExceptionTransformer; +import org.apache.commons.collections4.functors.FactoryTransformer; +import org.apache.commons.collections4.functors.IfTransformer; +import org.apache.commons.collections4.functors.InstantiateTransformer; +import org.apache.commons.collections4.functors.InvokerTransformer; +import org.apache.commons.collections4.functors.MapTransformer; +import org.apache.commons.collections4.functors.NOPTransformer; +import org.apache.commons.collections4.functors.PredicateTransformer; +import org.apache.commons.collections4.functors.StringValueTransformer; +import org.apache.commons.collections4.functors.SwitchTransformer; + +/** + * TransformerUtils provides reference implementations and + * utilities for the Transformer functor interface. The supplied transformers are: + *

        + *
      • Invoker - returns the result of a method call on the input object + *
      • Clone - returns a clone of the input object + *
      • Constant - always returns the same object + *
      • Closure - performs a Closure and returns the input object + *
      • Predicate - returns the result of the predicate as a Boolean + *
      • Factory - returns a new object from a factory + *
      • Chained - chains two or more transformers together + *
      • If - calls one transformer or another based on a predicate + *
      • Switch - calls one transformer based on one or more predicates + *
      • SwitchMap - calls one transformer looked up from a Map + *
      • Instantiate - the Class input object is instantiated + *
      • Map - returns an object from a supplied Map + *
      • Null - always returns null + *
      • NOP - returns the input object, which should be immutable + *
      • Exception - always throws an exception + *
      • StringValue - returns a java.lang.String representation of the input object + *
      + *

      + * Since v4.1 only transformers which are considered to be unsafe are + * Serializable. Transformers considered to be unsafe for serialization are: + *

        + *
      • Invoker + *
      • Clone + *
      • Instantiate + *
      + * + * @since 3.0 + * @version $Id: TransformerUtils.java 1714362 2015-11-14 20:38:02Z tn $ + */ +public class TransformerUtils { + + /** + * This class is not normally instantiated. + */ + private TransformerUtils() {} + + /** + * Gets a transformer that always throws an exception. + * This could be useful during testing as a placeholder. + * + * @param the input type + * @param the output type + * @return the transformer + * @see ExceptionTransformer + */ + public static Transformer exceptionTransformer() { + return ExceptionTransformer.exceptionTransformer(); + } + + /** + * Gets a transformer that always returns null. + * + * @param the input type + * @param the output type + * @return the transformer + * @see ConstantTransformer + */ + public static Transformer nullTransformer() { + return ConstantTransformer.nullTransformer(); + } + + /** + * Gets a transformer that returns the input object. + * The input object should be immutable to maintain the + * contract of Transformer (although this is not checked). + * + * @param the input/output type + * @return the transformer + * @see NOPTransformer + */ + public static Transformer nopTransformer() { + return NOPTransformer.nopTransformer(); + } + + /** + * Gets a transformer that returns a clone of the input object. + * The input object will be cloned using one of these techniques (in order): + *
        + *
      • public clone method + *
      • public copy constructor + *
      • serialization clone + *
          + * + * @param the input/output type + * @return the transformer + * @see CloneTransformer + */ + public static Transformer cloneTransformer() { + return CloneTransformer.cloneTransformer(); + } + + /** + * Creates a Transformer that will return the same object each time the + * transformer is used. + * + * @param the input type + * @param the output type + * @param constantToReturn the constant object to return each time in the transformer + * @return the transformer. + * @see ConstantTransformer + */ + public static Transformer constantTransformer(final O constantToReturn) { + return ConstantTransformer.constantTransformer(constantToReturn); + } + + /** + * Creates a Transformer that calls a Closure each time the transformer is used. + * The transformer returns the input object. + * + * @param the input/output type + * @param closure the closure to run each time in the transformer, not null + * @return the transformer + * @throws NullPointerException if the closure is null + * @see ClosureTransformer + */ + public static Transformer asTransformer(final Closure closure) { + return ClosureTransformer.closureTransformer(closure); + } + + /** + * Creates a Transformer that calls a Predicate each time the transformer is used. + * The transformer will return either Boolean.TRUE or Boolean.FALSE. + * + * @param the input type + * @param predicate the predicate to run each time in the transformer, not null + * @return the transformer + * @throws NullPointerException if the predicate is null + * @see PredicateTransformer + */ + public static Transformer asTransformer(final Predicate predicate) { + return PredicateTransformer.predicateTransformer(predicate); + } + + /** + * Creates a Transformer that calls a Factory each time the transformer is used. + * The transformer will return the value returned by the factory. + * + * @param the input type + * @param the output type + * @param factory the factory to run each time in the transformer, not null + * @return the transformer + * @throws NullPointerException if the factory is null + * @see FactoryTransformer + */ + public static Transformer asTransformer(final Factory factory) { + return FactoryTransformer.factoryTransformer(factory); + } + + /** + * Create a new Transformer that calls each transformer in turn, passing the + * result into the next transformer. + * + * @param the input/output type + * @param transformers an array of transformers to chain + * @return the transformer + * @throws NullPointerException if the transformers array or any of the transformers is null + * @see ChainedTransformer + */ + @SafeVarargs + public static Transformer chainedTransformer( + final Transformer... transformers) { + return ChainedTransformer.chainedTransformer(transformers); + } + + /** + * Create a new Transformer that calls each transformer in turn, passing the + * result into the next transformer. The ordering is that of the iterator() + * method on the collection. + * + * @param the input/output type + * @param transformers a collection of transformers to chain + * @return the transformer + * @throws NullPointerException if the transformers collection or any of the transformers is null + * @see ChainedTransformer + */ + public static Transformer chainedTransformer( + final Collection> transformers) { + return ChainedTransformer.chainedTransformer(transformers); + } + + /** + * Create a new Transformer that calls the transformer if the predicate is true, + * otherwise the input object is returned unchanged. + * + * @param the input / output type + * @param predicate the predicate to switch on + * @param trueTransformer the transformer called if the predicate is true + * @return the transformer + * @throws NullPointerException if either the predicate or transformer is null + * @see IfTransformer + * @since 4.1 + */ + public static Transformer ifTransformer(final Predicate predicate, + final Transformer trueTransformer) { + return IfTransformer.ifTransformer(predicate, trueTransformer); + } + + /** + * Create a new Transformer that calls one of two transformers depending + * on the specified predicate. + * + * @param the input type + * @param the output type + * @param predicate the predicate to switch on + * @param trueTransformer the transformer called if the predicate is true + * @param falseTransformer the transformer called if the predicate is false + * @return the transformer + * @throws NullPointerException if either the predicate or transformer is null + * @see IfTransformer + * @since 4.1 + */ + public static Transformer ifTransformer(final Predicate predicate, + final Transformer trueTransformer, + final Transformer falseTransformer) { + return IfTransformer.ifTransformer(predicate, trueTransformer, falseTransformer); + } + + /** + * Create a new Transformer that calls one of two transformers depending + * on the specified predicate. + * + * @param the input type + * @param the output type + * @param predicate the predicate to switch on + * @param trueTransformer the transformer called if the predicate is true + * @param falseTransformer the transformer called if the predicate is false + * @return the transformer + * @throws NullPointerException if either the predicate or transformer is null + * @see SwitchTransformer + * @deprecated as of 4.1, use {@link #ifTransformer(Predicate, Transformer, Transformer)) + */ + @SuppressWarnings("unchecked") + @Deprecated + public static Transformer switchTransformer(final Predicate predicate, + final Transformer trueTransformer, + final Transformer falseTransformer) { + return SwitchTransformer.switchTransformer(new Predicate[] { predicate }, + new Transformer[] { trueTransformer }, falseTransformer); + } + + /** + * Create a new Transformer that calls one of the transformers depending + * on the predicates. The transformer at array location 0 is called if the + * predicate at array location 0 returned true. Each predicate is evaluated + * until one returns true. If no predicates evaluate to true, null is returned. + * + * @param the input type + * @param the output type + * @param predicates an array of predicates to check + * @param transformers an array of transformers to call + * @return the transformer + * @throws NullPointerException if the either array is null + * @throws NullPointerException if any element in the arrays is null + * @throws IllegalArgumentException if the arrays have different sizes + * @see SwitchTransformer + */ + public static Transformer switchTransformer(final Predicate[] predicates, + final Transformer[] transformers) { + return SwitchTransformer.switchTransformer(predicates, transformers, null); + } + + /** + * Create a new Transformer that calls one of the transformers depending + * on the predicates. The transformer at array location 0 is called if the + * predicate at array location 0 returned true. Each predicate is evaluated + * until one returns true. If no predicates evaluate to true, the default + * transformer is called. If the default transformer is null, null is returned. + * + * @param the input type + * @param the output type + * @param predicates an array of predicates to check + * @param transformers an array of transformers to call + * @param defaultTransformer the default to call if no predicate matches, null means return null + * @return the transformer + * @throws NullPointerException if the either array is null + * @throws NullPointerException if any element in the arrays is null + * @throws IllegalArgumentException if the arrays have different sizes + * @see SwitchTransformer + */ + public static Transformer switchTransformer(final Predicate[] predicates, + final Transformer[] transformers, + final Transformer defaultTransformer) { + return SwitchTransformer.switchTransformer(predicates, transformers, defaultTransformer); + } + + /** + * Create a new Transformer that calls one of the transformers depending + * on the predicates. + *

          + * The Map consists of Predicate keys and Transformer values. A transformer + * is called if its matching predicate returns true. Each predicate is evaluated + * until one returns true. If no predicates evaluate to true, the default + * transformer is called. The default transformer is set in the map with a + * null key. If no default transformer is set, null will be returned in a default + * case. The ordering is that of the iterator() method on the entryset collection + * of the map. + * + * @param the input type + * @param the output type + * @param predicatesAndTransformers a map of predicates to transformers + * @return the transformer + * @throws NullPointerException if the map is null + * @throws NullPointerException if any transformer in the map is null + * @throws ClassCastException if the map elements are of the wrong type + * @see SwitchTransformer + */ + public static Transformer switchTransformer( + final Map, Transformer> predicatesAndTransformers) { + return SwitchTransformer.switchTransformer(predicatesAndTransformers); + } + + /** + * Create a new Transformer that uses the input object as a key to find the + * transformer to call. + *

          + * The Map consists of object keys and Transformer values. A transformer + * is called if the input object equals the key. If there is no match, the + * default transformer is called. The default transformer is set in the map + * using a null key. If no default is set, null will be returned in a default case. + * + * @param the input type + * @param the output type + * @param objectsAndTransformers a map of objects to transformers + * @return the transformer + * @throws NullPointerException if the map is null + * @throws NullPointerException if any transformer in the map is null + * @see SwitchTransformer + */ + @SuppressWarnings("unchecked") + public static Transformer switchMapTransformer( + final Map> objectsAndTransformers) { + + if (objectsAndTransformers == null) { + throw new NullPointerException("The object and transformer map must not be null"); + } + final Transformer def = objectsAndTransformers.remove(null); + final int size = objectsAndTransformers.size(); + final Transformer[] trs = new Transformer[size]; + final Predicate[] preds = new Predicate[size]; + int i = 0; + for (final Map.Entry> entry : objectsAndTransformers.entrySet()) { + preds[i] = EqualPredicate.equalPredicate(entry.getKey()); + trs[i++] = entry.getValue(); + } + return TransformerUtils.switchTransformer(preds, trs, def); + } + + /** + * Gets a Transformer that expects an input Class object that it will instantiate. + * + * @param the output type + * @return the transformer + * @see InstantiateTransformer + */ + public static Transformer, T> instantiateTransformer() { + return InstantiateTransformer.instantiateTransformer(); + } + + /** + * Creates a Transformer that expects an input Class object that it will + * instantiate. The constructor used is determined by the arguments specified + * to this method. + * + * @param the output type + * @param paramTypes parameter types for the constructor, can be null + * @param args the arguments to pass to the constructor, can be null + * @return the transformer + * @throws IllegalArgumentException if the paramTypes and args don't match + * @see InstantiateTransformer + */ + public static Transformer, T> instantiateTransformer( + final Class[] paramTypes, final Object[] args) { + return InstantiateTransformer.instantiateTransformer(paramTypes, args); + } + + /** + * Creates a Transformer that uses the passed in Map to transform the input + * object (as a simple lookup). + * + * @param the input type + * @param the output type + * @param map the map to use to transform the objects + * @return the transformer, or {@link ConstantTransformer#nullTransformer()} if the + * {@code map} is {@code null} + * @see MapTransformer + */ + public static Transformer mapTransformer(final Map map) { + return MapTransformer.mapTransformer(map); + } + + /** + * Gets a Transformer that invokes a method on the input object. + * The method must have no parameters. If the input object is null, + * null is returned. + *

          + * For example, TransformerUtils.invokerTransformer("getName"); + * will call the getName/code> method on the input object to + * determine the transformer result. + * + * @param the input type + * @param the output type + * @param methodName the method name to call on the input object, may not be null + * @return the transformer + * @throws NullPointerException if the methodName is null. + * @see InvokerTransformer + */ + public static Transformer invokerTransformer(final String methodName) { + return InvokerTransformer.invokerTransformer(methodName, null, null); + } + + /** + * Gets a Transformer that invokes a method on the input object. + * The method parameters are specified. If the input object is {@code null}, + * {@code null} is returned. + * + * @param the input type + * @param the output type + * @param methodName the name of the method + * @param paramTypes the parameter types + * @param args the arguments + * @return the transformer + * @throws NullPointerException if the method name is null + * @throws IllegalArgumentException if the paramTypes and args don't match + * @see InvokerTransformer + */ + public static Transformer invokerTransformer(final String methodName, final Class[] paramTypes, + final Object[] args) { + return InvokerTransformer.invokerTransformer(methodName, paramTypes, args); + } + + /** + * Gets a transformer that returns a java.lang.String + * representation of the input object. This is achieved via the + * toString method, null returns 'null'. + * + * @param the input type + * @return the transformer + * @see StringValueTransformer + */ + public static Transformer stringValueTransformer() { + return StringValueTransformer.stringValueTransformer(); + } + +} diff --git a/src/org/apache/commons/collections4/Trie.java b/src/org/apache/commons/collections4/Trie.java new file mode 100644 index 0000000..fe70e00 --- /dev/null +++ b/src/org/apache/commons/collections4/Trie.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import java.util.SortedMap; + +/** + * Defines the interface for a prefix tree, an ordered tree data structure. For + * more information, see Tries. + * + * @since 4.0 + * @version $Id: Trie.java 1543279 2013-11-19 00:54:31Z ggregory $ + */ +public interface Trie extends IterableSortedMap { + + /** + * Returns a view of this {@link Trie} of all elements that are prefixed + * by the given key. + *

          + * In a {@link Trie} with fixed size keys, this is essentially a + * {@link #get(Object)} operation. + *

          + * For example, if the {@link Trie} contains 'Anna', 'Anael', + * 'Analu', 'Andreas', 'Andrea', 'Andres', and 'Anatole', then + * a lookup of 'And' would return 'Andreas', 'Andrea', and 'Andres'. + * + * @param key the key used in the search + * @return a {@link SortedMap} view of this {@link Trie} with all elements whose + * key is prefixed by the search key + */ + SortedMap prefixMap(K key); + +} diff --git a/src/org/apache/commons/collections4/TrieUtils.java b/src/org/apache/commons/collections4/TrieUtils.java new file mode 100644 index 0000000..baf5186 --- /dev/null +++ b/src/org/apache/commons/collections4/TrieUtils.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +import org.apache.commons.collections4.trie.UnmodifiableTrie; + +/** + * A collection of {@link Trie} utilities. + * + * @since 4.0 + * @version $Id: TrieUtils.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TrieUtils { + + /** + * {@link TrieUtils} should not normally be instantiated. + */ + private TrieUtils() {} + + /** + * Returns an unmodifiable instance of a {@link Trie} + * + * @param the key type + * @param the value type + * @param trie the trie to make unmodifiable, must not be null + * @return an unmodifiable trie backed by the given trie + * @throws NullPointerException if trie is null + * + * @see java.util.Collections#unmodifiableMap(java.util.Map) + */ + public static Trie unmodifiableTrie(final Trie trie) { + return UnmodifiableTrie.unmodifiableTrie(trie); + } + +} diff --git a/src/org/apache/commons/collections4/Unmodifiable.java b/src/org/apache/commons/collections4/Unmodifiable.java new file mode 100644 index 0000000..1799462 --- /dev/null +++ b/src/org/apache/commons/collections4/Unmodifiable.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4; + +/** + * Marker interface for collections, maps and iterators that are unmodifiable. + *

          + * This interface enables testing such as: + *

          + * if (coll instanceof Unmodifiable) {
          + *   coll = new ArrayList(coll);
          + * }
          + * // now we know coll is modifiable
          + * 
          + * Of course all this only works if you use the Unmodifiable classes defined + * in this library. If you use the JDK unmodifiable class via {@code java.util Collections} + * then the interface won't be there. + * + * @since 3.0 + * @version $Id: Unmodifiable.java 1477779 2013-04-30 18:55:24Z tn $ + */ +public interface Unmodifiable { + // marker interface - no methods to implement +} diff --git a/src/org/apache/commons/collections4/bag/AbstractBagDecorator.java b/src/org/apache/commons/collections4/bag/AbstractBagDecorator.java new file mode 100644 index 0000000..ed0d6d3 --- /dev/null +++ b/src/org/apache/commons/collections4/bag/AbstractBagDecorator.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Set; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.collection.AbstractCollectionDecorator; + +/** + * Decorates another Bag to provide additional behaviour. + *

          + * Methods are forwarded directly to the decorated bag. + * + * @since 3.0 + * @version $Id: AbstractBagDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractBagDecorator + extends AbstractCollectionDecorator implements Bag { + + /** Serialization version */ + private static final long serialVersionUID = -3768146017343785417L; + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractBagDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + protected AbstractBagDecorator(final Bag bag) { + super(bag); + } + + /** + * Gets the bag being decorated. + * + * @return the decorated bag + */ + @Override + protected Bag decorated() { + return (Bag) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + @Override + public int getCount(final Object object) { + return decorated().getCount(object); + } + + @Override + public boolean add(final E object, final int count) { + return decorated().add(object, count); + } + + @Override + public boolean remove(final Object object, final int count) { + return decorated().remove(object, count); + } + + @Override + public Set uniqueSet() { + return decorated().uniqueSet(); + } + +} diff --git a/src/org/apache/commons/collections4/bag/AbstractMapBag.java b/src/org/apache/commons/collections4/bag/AbstractMapBag.java new file mode 100644 index 0000000..2829e7b --- /dev/null +++ b/src/org/apache/commons/collections4/bag/AbstractMapBag.java @@ -0,0 +1,625 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.set.UnmodifiableSet; + +import java.util.Set; + +/** + * Abstract implementation of the {@link Bag} interface to simplify the creation + * of subclass implementations. + *

          + * Subclasses specify a Map implementation to use as the internal storage. The + * map will be used to map bag elements to a number; the number represents the + * number of occurrences of that element in the bag. + * + * @since 3.0 (previously DefaultMapBag v2.0) + * @version $Id: AbstractMapBag.java 1684859 2015-06-11 11:57:24Z tn $ + */ +public abstract class AbstractMapBag implements Bag { + + /** The map to use to store the data */ + private transient Map map; + /** The current total size of the bag */ + private int size; + /** The modification count for fail fast iterators */ + private transient int modCount; + /** Unique view of the elements */ + private transient Set uniqueSet; + + /** + * Constructor needed for subclass serialisation. + */ + protected AbstractMapBag() { + super(); + } + + /** + * Constructor that assigns the specified Map as the backing store. The map + * must be empty and non-null. + * + * @param map the map to assign + */ + protected AbstractMapBag(final Map map) { + super(); + this.map = map; + } + + /** + * Utility method for implementations to access the map that backs this bag. + * Not intended for interactive use outside of subclasses. + * + * @return the map being used by the Bag + */ + protected Map getMap() { + return map; + } + + //----------------------------------------------------------------------- + /** + * Returns the number of elements in this bag. + * + * @return current size of the bag + */ + @Override + public int size() { + return size; + } + + /** + * Returns true if the underlying map is empty. + * + * @return true if bag is empty + */ + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Returns the number of occurrence of the given element in this bag by + * looking up its count in the underlying map. + * + * @param object the object to search for + * @return the number of occurrences of the object, zero if not found + */ + @Override + public int getCount(final Object object) { + final MutableInteger count = map.get(object); + if (count != null) { + return count.value; + } + return 0; + } + + //----------------------------------------------------------------------- + /** + * Determines if the bag contains the given element by checking if the + * underlying map contains the element as a key. + * + * @param object the object to search for + * @return true if the bag contains the given element + */ + @Override + public boolean contains(final Object object) { + return map.containsKey(object); + } + + /** + * Determines if the bag contains the given elements. + * + * @param coll the collection to check against + * @return true if the Bag contains all the collection + */ + @Override + public boolean containsAll(final Collection coll) { + if (coll instanceof Bag) { + return containsAll((Bag) coll); + } + return containsAll(new HashBag(coll)); + } + + /** + * Returns true if the bag contains all elements in the given + * collection, respecting cardinality. + * + * @param other the bag to check against + * @return true if the Bag contains all the collection + */ + boolean containsAll(final Bag other) { + final Iterator it = other.uniqueSet().iterator(); + while (it.hasNext()) { + final Object current = it.next(); + if (getCount(current) < other.getCount(current)) { + return false; + } + } + return true; + } + + //----------------------------------------------------------------------- + /** + * Gets an iterator over the bag elements. Elements present in the Bag more + * than once will be returned repeatedly. + * + * @return the iterator + */ + @Override + public Iterator iterator() { + return new BagIterator(this); + } + + /** + * Inner class iterator for the Bag. + */ + static class BagIterator implements Iterator { + private final AbstractMapBag parent; + private final Iterator> entryIterator; + private Map.Entry current; + private int itemCount; + private final int mods; + private boolean canRemove; + + /** + * Constructor. + * + * @param parent the parent bag + */ + public BagIterator(final AbstractMapBag parent) { + this.parent = parent; + this.entryIterator = parent.map.entrySet().iterator(); + this.current = null; + this.mods = parent.modCount; + this.canRemove = false; + } + + /** {@inheritDoc} */ + @Override + public boolean hasNext() { + return itemCount > 0 || entryIterator.hasNext(); + } + + /** {@inheritDoc} */ + @Override + public E next() { + if (parent.modCount != mods) { + throw new ConcurrentModificationException(); + } + if (itemCount == 0) { + current = entryIterator.next(); + itemCount = current.getValue().value; + } + canRemove = true; + itemCount--; + return current.getKey(); + } + + /** {@inheritDoc} */ + @Override + public void remove() { + if (parent.modCount != mods) { + throw new ConcurrentModificationException(); + } + if (canRemove == false) { + throw new IllegalStateException(); + } + final MutableInteger mut = current.getValue(); + if (mut.value > 1) { + mut.value--; + } else { + entryIterator.remove(); + } + parent.size--; + canRemove = false; + } + } + + //----------------------------------------------------------------------- + /** + * Adds a new element to the bag, incrementing its count in the underlying map. + * + * @param object the object to add + * @return true if the object was not already in the uniqueSet + */ + @Override + public boolean add(final E object) { + return add(object, 1); + } + + /** + * Adds a new element to the bag, incrementing its count in the map. + * + * @param object the object to search for + * @param nCopies the number of copies to add + * @return true if the object was not already in the uniqueSet + */ + @Override + public boolean add(final E object, final int nCopies) { + modCount++; + if (nCopies > 0) { + final MutableInteger mut = map.get(object); + size += nCopies; + if (mut == null) { + map.put(object, new MutableInteger(nCopies)); + return true; + } + mut.value += nCopies; + return false; + } + return false; + } + + /** + * Invokes {@link #add(Object)} for each element in the given collection. + * + * @param coll the collection to add + * @return true if this call changed the bag + */ + @Override + public boolean addAll(final Collection coll) { + boolean changed = false; + final Iterator i = coll.iterator(); + while (i.hasNext()) { + final boolean added = add(i.next()); + changed = changed || added; + } + return changed; + } + + //----------------------------------------------------------------------- + /** + * Clears the bag by clearing the underlying map. + */ + @Override + public void clear() { + modCount++; + map.clear(); + size = 0; + } + + /** + * Removes all copies of the specified object from the bag. + * + * @param object the object to remove + * @return true if the bag changed + */ + @Override + public boolean remove(final Object object) { + final MutableInteger mut = map.get(object); + if (mut == null) { + return false; + } + modCount++; + map.remove(object); + size -= mut.value; + return true; + } + + /** + * Removes a specified number of copies of an object from the bag. + * + * @param object the object to remove + * @param nCopies the number of copies to remove + * @return true if the bag changed + */ + @Override + public boolean remove(final Object object, final int nCopies) { + final MutableInteger mut = map.get(object); + if (mut == null) { + return false; + } + if (nCopies <= 0) { + return false; + } + modCount++; + if (nCopies < mut.value) { + mut.value -= nCopies; + size -= nCopies; + } else { + map.remove(object); + size -= mut.value; + } + return true; + } + + /** + * Removes objects from the bag according to their count in the specified + * collection. + * + * @param coll the collection to use + * @return true if the bag changed + */ + @Override + public boolean removeAll(final Collection coll) { + boolean result = false; + if (coll != null) { + final Iterator i = coll.iterator(); + while (i.hasNext()) { + final boolean changed = remove(i.next(), 1); + result = result || changed; + } + } + return result; + } + + /** + * Remove any members of the bag that are not in the given bag, respecting + * cardinality. + * + * @param coll the collection to retain + * @return true if this call changed the collection + */ + @Override + public boolean retainAll(final Collection coll) { + if (coll instanceof Bag) { + return retainAll((Bag) coll); + } + return retainAll(new HashBag(coll)); + } + + /** + * Remove any members of the bag that are not in the given bag, respecting + * cardinality. + * @see #retainAll(Collection) + * + * @param other the bag to retain + * @return true if this call changed the collection + */ + boolean retainAll(final Bag other) { + boolean result = false; + final Bag excess = new HashBag(); + final Iterator i = uniqueSet().iterator(); + while (i.hasNext()) { + final E current = i.next(); + final int myCount = getCount(current); + final int otherCount = other.getCount(current); + if (1 <= otherCount && otherCount <= myCount) { + excess.add(current, myCount - otherCount); + } else { + excess.add(current, myCount); + } + } + if (!excess.isEmpty()) { + result = removeAll(excess); + } + return result; + } + + //----------------------------------------------------------------------- + /** + * Mutable integer class for storing the data. + */ + protected static class MutableInteger { + /** The value of this mutable. */ + protected int value; + + /** + * Constructor. + * @param value the initial value + */ + MutableInteger(final int value) { + this.value = value; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableInteger == false) { + return false; + } + return ((MutableInteger) obj).value == value; + } + + @Override + public int hashCode() { + return value; + } + } + + //----------------------------------------------------------------------- + /** + * Returns an array of all of this bag's elements. + * + * @return an array of all of this bag's elements + */ + @Override + public Object[] toArray() { + final Object[] result = new Object[size()]; + int i = 0; + final Iterator it = map.keySet().iterator(); + while (it.hasNext()) { + final E current = it.next(); + for (int index = getCount(current); index > 0; index--) { + result[i++] = current; + } + } + return result; + } + + /** + * Returns an array of all of this bag's elements. + * If the input array has more elements than are in the bag, + * trailing elements will be set to null. + * + * @param the type of the array elements + * @param array the array to populate + * @return an array of all of this bag's elements + * @throws ArrayStoreException if the runtime type of the specified array is not + * a supertype of the runtime type of the elements in this list + * @throws NullPointerException if the specified array is null + */ + @Override + public T[] toArray(T[] array) { + final int size = size(); + if (array.length < size) { + @SuppressWarnings("unchecked") // safe as both are of type T + final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size); + array = unchecked; + } + + int i = 0; + final Iterator it = map.keySet().iterator(); + while (it.hasNext()) { + final E current = it.next(); + for (int index = getCount(current); index > 0; index--) { + // unsafe, will throw ArrayStoreException if types are not compatible, see javadoc + @SuppressWarnings("unchecked") + final T unchecked = (T) current; + array[i++] = unchecked; + } + } + while (i < array.length) { + array[i++] = null; + } + return array; + } + + /** + * Returns an unmodifiable view of the underlying map's key set. + * + * @return the set of unique elements in this bag + */ + @Override + public Set uniqueSet() { + if (uniqueSet == null) { + uniqueSet = UnmodifiableSet. unmodifiableSet(map.keySet()); + } + return uniqueSet; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * @param out the output stream + * @throws IOException any of the usual I/O related exceptions + */ + protected void doWriteObject(final ObjectOutputStream out) throws IOException { + out.writeInt(map.size()); + for (final Entry entry : map.entrySet()) { + out.writeObject(entry.getKey()); + out.writeInt(entry.getValue().value); + } + } + + /** + * Read the map in using a custom routine. + * @param map the map to use + * @param in the input stream + * @throws IOException any of the usual I/O related exceptions + * @throws ClassNotFoundException if the stream contains an object which class can not be loaded + * @throws ClassCastException if the stream does not contain the correct objects + */ + protected void doReadObject(final Map map, final ObjectInputStream in) + throws IOException, ClassNotFoundException { + this.map = map; + final int entrySize = in.readInt(); + for (int i = 0; i < entrySize; i++) { + @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect + final E obj = (E) in.readObject(); + final int count = in.readInt(); + map.put(obj, new MutableInteger(count)); + size += count; + } + } + + //----------------------------------------------------------------------- + /** + * Compares this Bag to another. This Bag equals another Bag if it contains + * the same number of occurrences of the same elements. + * + * @param object the Bag to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + if (object instanceof Bag == false) { + return false; + } + final Bag other = (Bag) object; + if (other.size() != size()) { + return false; + } + for (final E element : map.keySet()) { + if (other.getCount(element) != getCount(element)) { + return false; + } + } + return true; + } + + /** + * Gets a hash code for the Bag compatible with the definition of equals. + * The hash code is defined as the sum total of a hash code for each + * element. The per element hash code is defined as + * (e==null ? 0 : e.hashCode()) ^ noOccurances). This hash code + * is compatible with the Set interface. + * + * @return the hash code of the Bag + */ + @Override + public int hashCode() { + int total = 0; + for (final Entry entry : map.entrySet()) { + final E element = entry.getKey(); + final MutableInteger count = entry.getValue(); + total += (element == null ? 0 : element.hashCode()) ^ count.value; + } + return total; + } + + /** + * Implement a toString() method suitable for debugging. + * + * @return a debugging toString + */ + @Override + public String toString() { + if (size() == 0) { + return "[]"; + } + final StringBuilder buf = new StringBuilder(); + buf.append('['); + final Iterator it = uniqueSet().iterator(); + while (it.hasNext()) { + final Object current = it.next(); + final int count = getCount(current); + buf.append(count); + buf.append(':'); + buf.append(current); + if (it.hasNext()) { + buf.append(','); + } + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/src/org/apache/commons/collections4/bag/AbstractSortedBagDecorator.java b/src/org/apache/commons/collections4/bag/AbstractSortedBagDecorator.java new file mode 100644 index 0000000..bcd7472 --- /dev/null +++ b/src/org/apache/commons/collections4/bag/AbstractSortedBagDecorator.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Comparator; + +import org.apache.commons.collections4.SortedBag; + +/** + * Decorates another SortedBag to provide additional behaviour. + *

          + * Methods are forwarded directly to the decorated bag. + * + * @since 3.0 + * @version $Id: AbstractSortedBagDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractSortedBagDecorator + extends AbstractBagDecorator implements SortedBag { + + /** Serialization version */ + private static final long serialVersionUID = -8223473624050467718L; + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractSortedBagDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + protected AbstractSortedBagDecorator(final SortedBag bag) { + super(bag); + } + + /** + * Gets the bag being decorated. + * + * @return the decorated bag + */ + @Override + protected SortedBag decorated() { + return (SortedBag) super.decorated(); + } + + //----------------------------------------------------------------------- + + @Override + public E first() { + return decorated().first(); + } + + @Override + public E last() { + return decorated().last(); + } + + @Override + public Comparator comparator() { + return decorated().comparator(); + } + +} diff --git a/src/org/apache/commons/collections4/bag/CollectionBag.java b/src/org/apache/commons/collections4/bag/CollectionBag.java new file mode 100644 index 0000000..662ecaa --- /dev/null +++ b/src/org/apache/commons/collections4/bag/CollectionBag.java @@ -0,0 +1,243 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; + +import org.apache.commons.collections4.Bag; + +/** + * Decorates another {@link Bag} to comply with the Collection contract. + *

          + * By decorating an existing {@link Bag} instance with a {@link CollectionBag}, + * it can be safely passed on to methods that require Collection types that + * are fully compliant with the Collection contract. + *

          + * The method javadoc highlights the differences compared to the original Bag interface. + * + * @see Bag + * @param the type held in the bag + * @since 4.0 + * @version $Id: CollectionBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class CollectionBag extends AbstractBagDecorator { + + /** Serialization version */ + private static final long serialVersionUID = -2560033712679053143L; + + /** + * Factory method to create a bag that complies to the Collection contract. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @return a Bag that complies to the Collection contract + * @throws NullPointerException if bag is null + */ + public static Bag collectionBag(final Bag bag) { + return new CollectionBag(bag); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + public CollectionBag(final Bag bag) { + super(bag); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @throws ClassCastException if deserialised object has wrong type + */ + @SuppressWarnings("unchecked") // will throw CCE, see Javadoc + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + + //----------------------------------------------------------------------- + // Collection interface + //----------------------------------------------------------------------- + + /** + * (Change) + * Returns true if the bag contains all elements in + * the given collection, not respecting cardinality. That is, + * if the given collection coll contains at least one of + * every object contained in this object. + * + * @param coll the collection to check against + * @return true if the Bag contains at least one of every object in the collection + */ + @Override + public boolean containsAll(final Collection coll) { + final Iterator e = coll.iterator(); + while (e.hasNext()) { + if(!contains(e.next())) { + return false; + } + } + return true; + } + + /** + * (Change) + * Adds one copy of the specified object to the Bag. + *

          + * Since this method always increases the size of the bag, it + * will always return true. + * + * @param object the object to add + * @return true, always + */ + @Override + public boolean add(final E object) { + return add(object, 1); + } + + @Override + public boolean addAll(final Collection coll) { + boolean changed = false; + final Iterator i = coll.iterator(); + while (i.hasNext()) { + final boolean added = add(i.next(), 1); + changed = changed || added; + } + return changed; + } + + /** + * (Change) + * Removes the first occurrence of the given object from the bag. + *

          + * This will also remove the object from the {@link #uniqueSet()} if the + * bag contains no occurrence anymore of the object after this operation. + * + * @param object the object to remove + * @return true if this call changed the collection + */ + @Override + public boolean remove(final Object object) { + return remove(object, 1); + } + + /** + * (Change) + * Remove all elements represented in the given collection, + * not respecting cardinality. That is, remove all + * occurrences of every object contained in the given collection. + * + * @param coll the collection to remove + * @return true if this call changed the collection + */ + @Override + public boolean removeAll(final Collection coll) { + if (coll != null) { + boolean result = false; + final Iterator i = coll.iterator(); + while (i.hasNext()) { + final Object obj = i.next(); + final boolean changed = remove(obj, getCount(obj)); + result = result || changed; + } + return result; + } else { + // let the decorated bag handle the case of null argument + return decorated().removeAll(null); + } + } + + /** + * (Change) + * Remove any members of the bag that are not in the given collection, + * not respecting cardinality. That is, any object in the given + * collection coll will be retained in the bag with the same + * number of copies prior to this operation. All other objects will be + * completely removed from this bag. + *

          + * This implementation iterates over the elements of this bag, checking + * each element in turn to see if it's contained in coll. + * If it's not contained, it's removed from this bag. As a consequence, + * it is advised to use a collection type for coll that provides + * a fast (e.g. O(1)) implementation of {@link Collection#contains(Object)}. + * + * @param coll the collection to retain + * @return true if this call changed the collection + */ + @Override + public boolean retainAll(final Collection coll) { + if (coll != null) { + boolean modified = false; + final Iterator e = iterator(); + while (e.hasNext()) { + if (!coll.contains(e.next())) { + e.remove(); + modified = true; + } + } + return modified; + } else { + // let the decorated bag handle the case of null argument + return decorated().retainAll(null); + } + } + + //----------------------------------------------------------------------- + // Bag interface + //----------------------------------------------------------------------- + + /** + * (Change) + * Adds count copies of the specified object to the Bag. + *

          + * Since this method always increases the size of the bag, it + * will always return true. + * + * @param object the object to add + * @param count the number of copies to add + * @return true, always + */ + @Override + public boolean add(final E object, final int count) { + decorated().add(object, count); + return true; + } + +} diff --git a/src/org/apache/commons/collections4/bag/CollectionSortedBag.java b/src/org/apache/commons/collections4/bag/CollectionSortedBag.java new file mode 100644 index 0000000..0af350b --- /dev/null +++ b/src/org/apache/commons/collections4/bag/CollectionSortedBag.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; + +import org.apache.commons.collections4.SortedBag; + +/** + * Decorates another {@link SortedBag} to comply with the Collection contract. + * + * @since 4.0 + * @version $Id: CollectionSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class CollectionSortedBag extends AbstractSortedBagDecorator { + + /** Serialization version */ + private static final long serialVersionUID = -2560033712679053143L; + + /** + * Factory method to create a sorted bag that complies to the Collection contract. + * + * @param the type of the elements in the bag + * @param bag the sorted bag to decorate, must not be null + * @return a SortedBag that complies to the Collection contract + * @throws NullPointerException if bag is null + */ + public static SortedBag collectionSortedBag(final SortedBag bag) { + return new CollectionSortedBag(bag); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param bag the sorted bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + public CollectionSortedBag(final SortedBag bag) { + super(bag); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @throws ClassCastException if deserialised object has wrong type + */ + @SuppressWarnings("unchecked") // will throw CCE, see Javadoc + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + + //----------------------------------------------------------------------- + // Collection interface + //----------------------------------------------------------------------- + + @Override + public boolean containsAll(final Collection coll) { + final Iterator e = coll.iterator(); + while (e.hasNext()) { + if(!contains(e.next())) { + return false; + } + } + return true; + } + + @Override + public boolean add(final E object) { + return add(object, 1); + } + + @Override + public boolean addAll(final Collection coll) { + boolean changed = false; + final Iterator i = coll.iterator(); + while (i.hasNext()) { + final boolean added = add(i.next(), 1); + changed = changed || added; + } + return changed; + } + + @Override + public boolean remove(final Object object) { + return remove(object, 1); + } + + @Override + public boolean removeAll(final Collection coll) { + if (coll != null) { + boolean result = false; + final Iterator i = coll.iterator(); + while (i.hasNext()) { + final Object obj = i.next(); + final boolean changed = remove(obj, getCount(obj)); + result = result || changed; + } + return result; + } else { + // let the decorated bag handle the case of null argument + return decorated().removeAll(null); + } + } + + @Override + public boolean retainAll(final Collection coll) { + if (coll != null) { + boolean modified = false; + final Iterator e = iterator(); + while (e.hasNext()) { + if (!coll.contains(e.next())) { + e.remove(); + modified = true; + } + } + return modified; + } else { + // let the decorated bag handle the case of null argument + return decorated().retainAll(null); + } + } + + //----------------------------------------------------------------------- + // Bag interface + //----------------------------------------------------------------------- + + @Override + public boolean add(final E object, final int count) { + decorated().add(object, count); + return true; + } + +} diff --git a/src/org/apache/commons/collections4/bag/HashBag.java b/src/org/apache/commons/collections4/bag/HashBag.java new file mode 100644 index 0000000..64f2f3c --- /dev/null +++ b/src/org/apache/commons/collections4/bag/HashBag.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; + +/** + * Implements {@code Bag}, using a {@link HashMap} to provide the + * data storage. This is the standard implementation of a bag. + *

          + * A {@code Bag} stores each object in the collection together with a + * count of occurrences. Extra methods on the interface allow multiple copies + * of an object to be added or removed at once. It is important to read the + * interface javadoc carefully as several methods violate the + * {@link Collection} interface specification. + * + * @since 3.0 (previously in main package v2.0) + * @version $Id: HashBag.java 1685902 2015-06-16 20:13:13Z tn $ + */ +public class HashBag extends AbstractMapBag implements Serializable { + + /** Serial version lock */ + private static final long serialVersionUID = -6561115435802554013L; + + /** + * Constructs an empty {@link HashBag}. + */ + public HashBag() { + super(new HashMap()); + } + + /** + * Constructs a bag containing all the members of the given collection. + * + * @param coll a collection to copy into this bag + */ + public HashBag(final Collection coll) { + this(); + addAll(coll); + } + + //----------------------------------------------------------------------- + /** + * Write the bag out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + super.doWriteObject(out); + } + + /** + * Read the bag in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + super.doReadObject(new HashMap(), in); + } + +} diff --git a/src/org/apache/commons/collections4/bag/PredicatedBag.java b/src/org/apache/commons/collections4/bag/PredicatedBag.java new file mode 100644 index 0000000..6a3c51e --- /dev/null +++ b/src/org/apache/commons/collections4/bag/PredicatedBag.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Set; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.collection.PredicatedCollection; + +/** + * Decorates another {@link Bag} to validate that additions + * match a specified predicate. + *

          + * This bag exists to provide validation for the decorated bag. + * It is normally created to decorate an empty bag. + * If an object cannot be added to the bag, an {@link IllegalArgumentException} is thrown. + *

          + * One usage would be to ensure that no null entries are added to the bag. + *

          + * Bag bag = PredicatedBag.predicatedBag(new HashBag(), NotNullPredicate.INSTANCE);
          + * 
          + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: PredicatedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedBag extends PredicatedCollection implements Bag { + + /** Serialization version */ + private static final long serialVersionUID = -2575833140344736876L; + + /** + * Factory method to create a predicated (validating) bag. + *

          + * If there are any elements already in the bag being decorated, they + * are validated. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated Bag + * @throws NullPointerException if bag or predicate is null + * @throws IllegalArgumentException if the bag contains invalid elements + * @since 4.0 + */ + public static PredicatedBag predicatedBag(final Bag bag, final Predicate predicate) { + return new PredicatedBag(bag, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

          + * If there are any elements already in the bag being decorated, they + * are validated. + * + * @param bag the bag to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if bag or predicate is null + * @throws IllegalArgumentException if the bag contains invalid elements + */ + protected PredicatedBag(final Bag bag, final Predicate predicate) { + super(bag, predicate); + } + + /** + * Gets the decorated bag. + * + * @return the decorated bag + */ + @Override + protected Bag decorated() { + return (Bag) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + @Override + public boolean add(final E object, final int count) { + validate(object); + return decorated().add(object, count); + } + + @Override + public boolean remove(final Object object, final int count) { + return decorated().remove(object, count); + } + + @Override + public Set uniqueSet() { + return decorated().uniqueSet(); + } + + @Override + public int getCount(final Object object) { + return decorated().getCount(object); + } + +} diff --git a/src/org/apache/commons/collections4/bag/PredicatedSortedBag.java b/src/org/apache/commons/collections4/bag/PredicatedSortedBag.java new file mode 100644 index 0000000..6af1881 --- /dev/null +++ b/src/org/apache/commons/collections4/bag/PredicatedSortedBag.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Comparator; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.SortedBag; + +/** + * Decorates another {@link SortedBag} to validate that additions + * match a specified predicate. + *

          + * This bag exists to provide validation for the decorated bag. + * It is normally created to decorate an empty bag. + * If an object cannot be added to the bag, an {@link IllegalArgumentException} is thrown. + *

          + * One usage would be to ensure that no null entries are added to the bag. + *

          + * SortedBag bag = PredicatedSortedBag.predicatedSortedBag(new TreeBag(), NotNullPredicate.INSTANCE);
          + * 
          + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: PredicatedSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedSortedBag extends PredicatedBag implements SortedBag { + + /** Serialization version */ + private static final long serialVersionUID = 3448581314086406616L; + + /** + * Factory method to create a predicated (validating) bag. + *

          + * If there are any elements already in the bag being decorated, they + * are validated. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated SortedBag + * @throws NullPointerException if bag or predicate is null + * @throws IllegalArgumentException if the bag contains invalid elements + * @since 4.0 + */ + public static PredicatedSortedBag predicatedSortedBag(final SortedBag bag, + final Predicate predicate) { + return new PredicatedSortedBag(bag, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

          If there are any elements already in the bag being decorated, they + * are validated. + * + * @param bag the bag to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if bag or predicate is null + * @throws IllegalArgumentException if the bag contains invalid elements + */ + protected PredicatedSortedBag(final SortedBag bag, final Predicate predicate) { + super(bag, predicate); + } + + /** + * Gets the decorated sorted bag. + * + * @return the decorated bag + */ + @Override + protected SortedBag decorated() { + return (SortedBag) super.decorated(); + } + + //----------------------------------------------------------------------- + + @Override + public E first() { + return decorated().first(); + } + + @Override + public E last() { + return decorated().last(); + } + + @Override + public Comparator comparator() { + return decorated().comparator(); + } + +} diff --git a/src/org/apache/commons/collections4/bag/SynchronizedBag.java b/src/org/apache/commons/collections4/bag/SynchronizedBag.java new file mode 100644 index 0000000..7fb5472 --- /dev/null +++ b/src/org/apache/commons/collections4/bag/SynchronizedBag.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Set; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.collection.SynchronizedCollection; + +/** + * Decorates another {@link Bag} to synchronize its behaviour + * for a multi-threaded environment. + *

          + * Methods are synchronized, then forwarded to the decorated bag. + * Iterators must be separately synchronized around the loop. + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: SynchronizedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class SynchronizedBag extends SynchronizedCollection implements Bag { + + /** Serialization version */ + private static final long serialVersionUID = 8084674570753837109L; + + /** + * Factory method to create a synchronized bag. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @return a new synchronized Bag + * @throws NullPointerException if bag is null + * @since 4.0 + */ + public static SynchronizedBag synchronizedBag(final Bag bag) { + return new SynchronizedBag(bag); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + protected SynchronizedBag(final Bag bag) { + super(bag); + } + + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @param lock the lock to use, must not be null + * @throws NullPointerException if bag or lock is null + */ + protected SynchronizedBag(final Bag bag, final Object lock) { + super(bag, lock); + } + + /** + * Gets the bag being decorated. + * + * @return the decorated bag + */ + protected Bag getBag() { + return (Bag) decorated(); + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + synchronized (lock) { + return getBag().equals(object); + } + } + + @Override + public int hashCode() { + synchronized (lock) { + return getBag().hashCode(); + } + } + + //----------------------------------------------------------------------- + + @Override + public boolean add(final E object, final int count) { + synchronized (lock) { + return getBag().add(object, count); + } + } + + @Override + public boolean remove(final Object object, final int count) { + synchronized (lock) { + return getBag().remove(object, count); + } + } + + @Override + public Set uniqueSet() { + synchronized (lock) { + final Set set = getBag().uniqueSet(); + return new SynchronizedBagSet(set, lock); + } + } + + @Override + public int getCount(final Object object) { + synchronized (lock) { + return getBag().getCount(object); + } + } + + //----------------------------------------------------------------------- + /** + * Synchronized Set for the Bag class. + */ + class SynchronizedBagSet extends SynchronizedCollection implements Set { + /** Serialization version */ + private static final long serialVersionUID = 2990565892366827855L; + + /** + * Constructor. + * @param set the set to decorate + * @param lock the lock to use, shared with the bag + */ + SynchronizedBagSet(final Set set, final Object lock) { + super(set, lock); + } + } + +} diff --git a/src/org/apache/commons/collections4/bag/SynchronizedSortedBag.java b/src/org/apache/commons/collections4/bag/SynchronizedSortedBag.java new file mode 100644 index 0000000..f945f28 --- /dev/null +++ b/src/org/apache/commons/collections4/bag/SynchronizedSortedBag.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Comparator; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.SortedBag; + +/** + * Decorates another {@link SortedBag} to synchronize its behaviour + * for a multi-threaded environment. + *

          + * Methods are synchronized, then forwarded to the decorated bag. + * Iterators must be separately synchronized around the loop. + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: SynchronizedSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class SynchronizedSortedBag extends SynchronizedBag implements SortedBag { + + /** Serialization version */ + private static final long serialVersionUID = 722374056718497858L; + + /** + * Factory method to create a synchronized sorted bag. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @return a new synchronized SortedBag + * @throws NullPointerException if bag is null + * @since 4.0 + */ + public static SynchronizedSortedBag synchronizedSortedBag(final SortedBag bag) { + return new SynchronizedSortedBag(bag); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + protected SynchronizedSortedBag(final SortedBag bag) { + super(bag); + } + + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @param lock the lock to use, must not be null + * @throws NullPointerException if bag or lock is null + */ + protected SynchronizedSortedBag(final Bag bag, final Object lock) { + super(bag, lock); + } + + /** + * Gets the bag being decorated. + * + * @return the decorated bag + */ + protected SortedBag getSortedBag() { + return (SortedBag) decorated(); + } + + //----------------------------------------------------------------------- + + @Override + public synchronized E first() { + synchronized (lock) { + return getSortedBag().first(); + } + } + + @Override + public synchronized E last() { + synchronized (lock) { + return getSortedBag().last(); + } + } + + @Override + public synchronized Comparator comparator() { + synchronized (lock) { + return getSortedBag().comparator(); + } + } + +} diff --git a/src/org/apache/commons/collections4/bag/TransformedBag.java b/src/org/apache/commons/collections4/bag/TransformedBag.java new file mode 100644 index 0000000..50825c9 --- /dev/null +++ b/src/org/apache/commons/collections4/bag/TransformedBag.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Set; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.collection.TransformedCollection; +import org.apache.commons.collections4.set.TransformedSet; + +/** + * Decorates another {@link Bag} to transform objects that are added. + *

          + * The add methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: TransformedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedBag extends TransformedCollection implements Bag { + + /** Serialization version */ + private static final long serialVersionUID = 5421170911299074185L; + + /** + * Factory method to create a transforming bag. + *

          + * If there are any elements already in the bag being decorated, they + * are NOT transformed. Contrast this with {@link #transformedBag(Bag, Transformer)}. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed Bag + * @throws NullPointerException if bag or transformer is null + * @since 4.0 + */ + public static Bag transformingBag(final Bag bag, final Transformer transformer) { + return new TransformedBag(bag, transformer); + } + + /** + * Factory method to create a transforming bag that will transform + * existing contents of the specified bag. + *

          + * If there are any elements already in the bag being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingBag(Bag, Transformer)}. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed Bag + * @throws NullPointerException if bag or transformer is null + * @since 4.0 + */ + public static Bag transformedBag(final Bag bag, final Transformer transformer) { + final TransformedBag decorated = new TransformedBag(bag, transformer); + if (bag.size() > 0) { + @SuppressWarnings("unchecked") // Bag is of type E + final E[] values = (E[]) bag.toArray(); // NOPMD - false positive for generics + bag.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

          + * If there are any elements already in the bag being decorated, they + * are NOT transformed. + * + * @param bag the bag to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if bag or transformer is null + */ + protected TransformedBag(final Bag bag, final Transformer transformer) { + super(bag, transformer); + } + + /** + * Gets the decorated bag. + * + * @return the decorated bag + */ + protected Bag getBag() { + return (Bag) decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + @Override + public int getCount(final Object object) { + return getBag().getCount(object); + } + + @Override + public boolean remove(final Object object, final int nCopies) { + return getBag().remove(object, nCopies); + } + + //----------------------------------------------------------------------- + + @Override + public boolean add(final E object, final int nCopies) { + return getBag().add(transform(object), nCopies); + } + + @Override + public Set uniqueSet() { + final Set set = getBag().uniqueSet(); + return TransformedSet.transformingSet(set, transformer); + } + +} diff --git a/src/org/apache/commons/collections4/bag/TransformedSortedBag.java b/src/org/apache/commons/collections4/bag/TransformedSortedBag.java new file mode 100644 index 0000000..54557db --- /dev/null +++ b/src/org/apache/commons/collections4/bag/TransformedSortedBag.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.util.Comparator; + +import org.apache.commons.collections4.SortedBag; +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another {@link SortedBag} to transform objects that are added. + *

          + * The add methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: TransformedSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedSortedBag extends TransformedBag implements SortedBag { + + /** Serialization version */ + private static final long serialVersionUID = -251737742649401930L; + + /** + * Factory method to create a transforming sorted bag. + *

          + * If there are any elements already in the bag being decorated, they + * are NOT transformed. Contrast this with {@link #transformedSortedBag(SortedBag, Transformer)}. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed SortedBag + * @throws NullPointerException if bag or transformer is null + * @since 4.0 + */ + public static TransformedSortedBag transformingSortedBag(final SortedBag bag, + final Transformer transformer) { + return new TransformedSortedBag(bag, transformer); + } + + /** + * Factory method to create a transforming sorted bag that will transform + * existing contents of the specified sorted bag. + *

          + * If there are any elements already in the bag being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingSortedBag(SortedBag, Transformer)}. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed SortedBag + * @throws NullPointerException if bag or transformer is null + * @since 4.0 + */ + public static TransformedSortedBag transformedSortedBag(final SortedBag bag, + final Transformer transformer) { + + final TransformedSortedBag decorated = new TransformedSortedBag(bag, transformer); + if (bag.size() > 0) { + @SuppressWarnings("unchecked") // bag is type E + final E[] values = (E[]) bag.toArray(); // NOPMD - false positive for generics + bag.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

          + * If there are any elements already in the bag being decorated, they + * are NOT transformed. + * + * @param bag the bag to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if bag or transformer is null + */ + protected TransformedSortedBag(final SortedBag bag, final Transformer transformer) { + super(bag, transformer); + } + + /** + * Gets the decorated bag. + * + * @return the decorated bag + */ + protected SortedBag getSortedBag() { + return (SortedBag) decorated(); + } + + //----------------------------------------------------------------------- + + @Override + public E first() { + return getSortedBag().first(); + } + + @Override + public E last() { + return getSortedBag().last(); + } + + @Override + public Comparator comparator() { + return getSortedBag().comparator(); + } + +} diff --git a/src/org/apache/commons/collections4/bag/TreeBag.java b/src/org/apache/commons/collections4/bag/TreeBag.java new file mode 100644 index 0000000..3db2c7f --- /dev/null +++ b/src/org/apache/commons/collections4/bag/TreeBag.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.Comparator; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.commons.collections4.SortedBag; + +/** + * Implements {@link SortedBag}, using a {@link TreeMap} to provide the data storage. + * This is the standard implementation of a sorted bag. + *

          + * Order will be maintained among the bag members and can be viewed through the iterator. + *

          + * A {@link org.apache.commons.collections4.Bag Bag} stores each object in the collection + * together with a count of occurrences. Extra methods on the interface allow multiple + * copies of an object to be added or removed at once. It is important to read the interface + * javadoc carefully as several methods violate the {@link Collection} interface specification. + * + * @since 3.0 (previously in main package v2.0) + * @version $Id: TreeBag.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public class TreeBag extends AbstractMapBag implements SortedBag, Serializable { + + /** Serial version lock */ + private static final long serialVersionUID = -7740146511091606676L; + + /** + * Constructs an empty {@link TreeBag}. + */ + public TreeBag() { + super(new TreeMap()); + } + + /** + * Constructs an empty bag that maintains order on its unique representative + * members according to the given {@link Comparator}. + * + * @param comparator the comparator to use + */ + public TreeBag(final Comparator comparator) { + super(new TreeMap(comparator)); + } + + /** + * Constructs a {@link TreeBag} containing all the members of the + * specified collection. + * + * @param coll the collection to copy into the bag + */ + public TreeBag(final Collection coll) { + this(); + addAll(coll); + } + + //----------------------------------------------------------------------- + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if the object to be added does not implement + * {@link Comparable} and the {@link TreeBag} is using natural ordering + * @throws NullPointerException if the specified key is null and this bag uses + * natural ordering, or its comparator does not permit null keys + */ + @Override + public boolean add(final E object) { + if(comparator() == null && !(object instanceof Comparable)) { + if (object == null) { + throw new NullPointerException(); + } + throw new IllegalArgumentException("Objects of type " + object.getClass() + " cannot be added to " + + "a naturally ordered TreeBag as it does not implement Comparable"); + } + return super.add(object); + } + + //----------------------------------------------------------------------- + + @Override + public E first() { + return getMap().firstKey(); + } + + @Override + public E last() { + return getMap().lastKey(); + } + + @Override + public Comparator comparator() { + return getMap().comparator(); + } + + @Override + protected SortedMap getMap() { + return (SortedMap) super.getMap(); + } + + //----------------------------------------------------------------------- + /** + * Write the bag out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(comparator()); + super.doWriteObject(out); + } + + /** + * Read the bag in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect + final Comparator comp = (Comparator) in.readObject(); + super.doReadObject(new TreeMap(comp), in); + } + +} diff --git a/src/org/apache/commons/collections4/bag/UnmodifiableBag.java b/src/org/apache/commons/collections4/bag/UnmodifiableBag.java new file mode 100644 index 0000000..cd53fbf --- /dev/null +++ b/src/org/apache/commons/collections4/bag/UnmodifiableBag.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another {@link Bag} to ensure it can't be altered. + *

          + * This class is Serializable from Commons Collections 3.1. + *

          + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableBag + extends AbstractBagDecorator implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = -1873799975157099624L; + + /** + * Factory method to create an unmodifiable bag. + *

          + * If the bag passed in is already unmodifiable, it is returned. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @return an unmodifiable Bag + * @throws NullPointerException if bag is null + * @since 4.0 + */ + public static Bag unmodifiableBag(final Bag bag) { + if (bag instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final Bag tmpBag = (Bag) bag; + return tmpBag; + } + return new UnmodifiableBag(bag); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableBag(final Bag bag) { + super((Bag) bag); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @throws ClassCastException if deserialised object has wrong type + */ + @SuppressWarnings("unchecked") // will throw CCE, see Javadoc + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator. unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public boolean add(final E object, final int count) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object, final int count) { + throw new UnsupportedOperationException(); + } + + @Override + public Set uniqueSet() { + final Set set = decorated().uniqueSet(); + return UnmodifiableSet. unmodifiableSet(set); + } + +} diff --git a/src/org/apache/commons/collections4/bag/UnmodifiableSortedBag.java b/src/org/apache/commons/collections4/bag/UnmodifiableSortedBag.java new file mode 100644 index 0000000..f4465cd --- /dev/null +++ b/src/org/apache/commons/collections4/bag/UnmodifiableSortedBag.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bag; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import org.apache.commons.collections4.SortedBag; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another {@link SortedBag} to ensure it can't be altered. + *

          + * This class is Serializable from Commons Collections 3.1. + *

          + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableSortedBag + extends AbstractSortedBagDecorator implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = -3190437252665717841L; + + /** + * Factory method to create an unmodifiable bag. + *

          + * If the bag passed in is already unmodifiable, it is returned. + * + * @param the type of the elements in the bag + * @param bag the bag to decorate, must not be null + * @return an unmodifiable SortedBag + * @throws NullPointerException if bag is null + * @since 4.0 + */ + public static SortedBag unmodifiableSortedBag(final SortedBag bag) { + if (bag instanceof Unmodifiable) { + return bag; + } + return new UnmodifiableSortedBag(bag); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param bag the bag to decorate, must not be null + * @throws NullPointerException if bag is null + */ + private UnmodifiableSortedBag(final SortedBag bag) { + super(bag); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @throws ClassCastException if deserialised object has wrong type + */ + @SuppressWarnings("unchecked") // will throw CCE, see Javadoc + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public boolean add(final E object, final int count) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object, final int count) { + throw new UnsupportedOperationException(); + } + + @Override + public Set uniqueSet() { + final Set set = decorated().uniqueSet(); + return UnmodifiableSet.unmodifiableSet(set); + } + +} diff --git a/src/org/apache/commons/collections4/bag/package-info.java b/src/org/apache/commons/collections4/bag/package-info.java new file mode 100644 index 0000000..a8da5ca --- /dev/null +++ b/src/org/apache/commons/collections4/bag/package-info.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the {@link org.apache.commons.collections4.Bag Bag} and + * {@link org.apache.commons.collections4.SortedBag SortedBag} interfaces. + * A bag stores an object and a count of the number of occurrences of the object. + *

          + * The following implementations are provided in the package: + *

            + *
          • HashBag - implementation that uses a HashMap to store the data + *
          • TreeBag - implementation that uses a TreeMap to store the data + *
          + *

          + * The following decorators are provided in the package: + *

            + *
          • Synchronized - synchronizes method access for multi-threaded environments + *
          • Unmodifiable - ensures the bag cannot be altered + *
          • Predicated - ensures that only elements that are valid according to a predicate can be added + *
          • Transformed - transforms each element added to the bag + *
          • Collection - ensures compliance with the java.util.Collection contract + *
          + * + * @version $Id: package-info.java 1540804 2013-11-11 18:58:31Z tn $ + */ +package org.apache.commons.collections4.bag; diff --git a/src/org/apache/commons/collections4/bidimap/AbstractBidiMapDecorator.java b/src/org/apache/commons/collections4/bidimap/AbstractBidiMapDecorator.java new file mode 100644 index 0000000..f470916 --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/AbstractBidiMapDecorator.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.util.Set; + +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.map.AbstractMapDecorator; + +/** + * Provides a base decorator that enables additional functionality to be added + * to a BidiMap via decoration. + *

          + * Methods are forwarded directly to the decorated map. + *

          + * This implementation does not perform any special processing with the map views. + * Instead it simply returns the set/collection from the wrapped map. This may be + * undesirable, for example if you are trying to write a validating implementation + * it would provide a loophole around the validation. + * But, you might want that loophole, so this class is kept simple. + * + * @since 3.0 + * @version $Id: AbstractBidiMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractBidiMapDecorator + extends AbstractMapDecorator implements BidiMap { + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if the collection is null + */ + protected AbstractBidiMapDecorator(final BidiMap map) { + super(map); + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + @Override + protected BidiMap decorated() { + return (BidiMap) super.decorated(); + } + + //----------------------------------------------------------------------- + @Override + public MapIterator mapIterator() { + return decorated().mapIterator(); + } + + @Override + public K getKey(final Object value) { + return decorated().getKey(value); + } + + @Override + public K removeValue(final Object value) { + return decorated().removeValue(value); + } + + @Override + public BidiMap inverseBidiMap() { + return decorated().inverseBidiMap(); + } + + @Override + public Set values() { + return decorated().values(); + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java b/src/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java new file mode 100644 index 0000000..7c24f5e --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.java @@ -0,0 +1,805 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.ResettableIterator; +import org.apache.commons.collections4.collection.AbstractCollectionDecorator; +import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; +import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator; + +/** + * Abstract {@link BidiMap} implemented using two maps. + *

          + * An implementation can be written simply by implementing the + * {@link #createBidiMap(Map, Map, BidiMap)} method. + * + * @see DualHashBidiMap + * @see DualTreeBidiMap + * @since 3.0 + * @version $Id: AbstractDualBidiMap.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public abstract class AbstractDualBidiMap implements BidiMap { + + /** + * Normal delegate map. + */ + transient Map normalMap; + + /** + * Reverse delegate map. + */ + transient Map reverseMap; + + /** + * Inverse view of this map. + */ + transient BidiMap inverseBidiMap = null; + + /** + * View of the keys. + */ + transient Set keySet = null; + + /** + * View of the values. + */ + transient Set values = null; + + /** + * View of the entries. + */ + transient Set> entrySet = null; + + /** + * Creates an empty map, initialised by createMap. + *

          + * This constructor remains in place for deserialization. + * All other usage is deprecated in favour of + * {@link #AbstractDualBidiMap(Map, Map)}. + */ + protected AbstractDualBidiMap() { + super(); + } + + /** + * Creates an empty map using the two maps specified as storage. + *

          + * The two maps must be a matching pair, normal and reverse. + * They will typically both be empty. + *

          + * Neither map is validated, so nulls may be passed in. + * If you choose to do this then the subclass constructor must populate + * the maps[] instance variable itself. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @since 3.1 + */ + protected AbstractDualBidiMap(final Map normalMap, final Map reverseMap) { + super(); + this.normalMap = normalMap; + this.reverseMap = reverseMap; + } + + /** + * Constructs a map that decorates the specified maps, + * used by the subclass createBidiMap implementation. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseBidiMap the inverse BidiMap + */ + protected AbstractDualBidiMap(final Map normalMap, final Map reverseMap, + final BidiMap inverseBidiMap) { + super(); + this.normalMap = normalMap; + this.reverseMap = reverseMap; + this.inverseBidiMap = inverseBidiMap; + } + + /** + * Creates a new instance of the subclass. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseMap this map, which is the inverse in the new map + * @return the inverse map + */ + protected abstract BidiMap createBidiMap(Map normalMap, Map reverseMap, BidiMap inverseMap); + + // Map delegation + //----------------------------------------------------------------------- + + @Override + public V get(final Object key) { + return normalMap.get(key); + } + + @Override + public int size() { + return normalMap.size(); + } + + @Override + public boolean isEmpty() { + return normalMap.isEmpty(); + } + + @Override + public boolean containsKey(final Object key) { + return normalMap.containsKey(key); + } + + @Override + public boolean equals(final Object obj) { + return normalMap.equals(obj); + } + + @Override + public int hashCode() { + return normalMap.hashCode(); + } + + @Override + public String toString() { + return normalMap.toString(); + } + + // BidiMap changes + //----------------------------------------------------------------------- + + @Override + public V put(final K key, final V value) { + if (normalMap.containsKey(key)) { + reverseMap.remove(normalMap.get(key)); + } + if (reverseMap.containsKey(value)) { + normalMap.remove(reverseMap.get(value)); + } + final V obj = normalMap.put(key, value); + reverseMap.put(value, key); + return obj; + } + + @Override + public void putAll(final Map map) { + for (final Map.Entry entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + @Override + public V remove(final Object key) { + V value = null; + if (normalMap.containsKey(key)) { + value = normalMap.remove(key); + reverseMap.remove(value); + } + return value; + } + + @Override + public void clear() { + normalMap.clear(); + reverseMap.clear(); + } + + @Override + public boolean containsValue(final Object value) { + return reverseMap.containsKey(value); + } + + // BidiMap + //----------------------------------------------------------------------- + /** + * Obtains a MapIterator over the map. + * The iterator implements ResetableMapIterator. + * This implementation relies on the entrySet iterator. + *

          + * The setValue() methods only allow a new value to be set. + * If the value being set is already in the map, an IllegalArgumentException + * is thrown (as setValue cannot change the size of the map). + * + * @return a map iterator + */ + @Override + public MapIterator mapIterator() { + return new BidiMapIterator(this); + } + + @Override + public K getKey(final Object value) { + return reverseMap.get(value); + } + + @Override + public K removeValue(final Object value) { + K key = null; + if (reverseMap.containsKey(value)) { + key = reverseMap.remove(value); + normalMap.remove(key); + } + return key; + } + + @Override + public BidiMap inverseBidiMap() { + if (inverseBidiMap == null) { + inverseBidiMap = createBidiMap(reverseMap, normalMap, this); + } + return inverseBidiMap; + } + + // Map views + //----------------------------------------------------------------------- + /** + * Gets a keySet view of the map. + * Changes made on the view are reflected in the map. + * The set supports remove and clear but not add. + * + * @return the keySet view + */ + @Override + public Set keySet() { + if (keySet == null) { + keySet = new KeySet(this); + } + return keySet; + } + + /** + * Creates a key set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @param iterator the iterator to decorate + * @return the keySet iterator + */ + protected Iterator createKeySetIterator(final Iterator iterator) { + return new KeySetIterator(iterator, this); + } + + /** + * Gets a values view of the map. + * Changes made on the view are reflected in the map. + * The set supports remove and clear but not add. + * + * @return the values view + */ + @Override + public Set values() { + if (values == null) { + values = new Values(this); + } + return values; + } + + /** + * Creates a values iterator. + * Subclasses can override this to return iterators with different properties. + * + * @param iterator the iterator to decorate + * @return the values iterator + */ + protected Iterator createValuesIterator(final Iterator iterator) { + return new ValuesIterator(iterator, this); + } + + /** + * Gets an entrySet view of the map. + * Changes made on the set are reflected in the map. + * The set supports remove and clear but not add. + *

          + * The Map Entry setValue() method only allow a new value to be set. + * If the value being set is already in the map, an IllegalArgumentException + * is thrown (as setValue cannot change the size of the map). + * + * @return the entrySet view + */ + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = new EntrySet(this); + } + return entrySet; + } + + /** + * Creates an entry set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @param iterator the iterator to decorate + * @return the entrySet iterator + */ + protected Iterator> createEntrySetIterator(final Iterator> iterator) { + return new EntrySetIterator(iterator, this); + } + + //----------------------------------------------------------------------- + /** + * Inner class View. + */ + protected static abstract class View extends AbstractCollectionDecorator { + + /** Generated serial version ID. */ + private static final long serialVersionUID = 4621510560119690639L; + + /** The parent map */ + protected final AbstractDualBidiMap parent; + + /** + * Constructs a new view of the BidiMap. + * + * @param coll the collection view being decorated + * @param parent the parent BidiMap + */ + protected View(final Collection coll, final AbstractDualBidiMap parent) { + super(coll); + this.parent = parent; + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + @Override + public boolean removeAll(final Collection coll) { + if (parent.isEmpty() || coll.isEmpty()) { + return false; + } + boolean modified = false; + final Iterator it = coll.iterator(); + while (it.hasNext()) { + modified |= remove(it.next()); + } + return modified; + } + + /** + * {@inheritDoc} + *

          + * This implementation iterates over the elements of this bidi map, checking each element in + * turn to see if it's contained in coll. If it's not contained, it's removed + * from this bidi map. As a consequence, it is advised to use a collection type for + * coll that provides a fast (e.g. O(1)) implementation of + * {@link Collection#contains(Object)}. + */ + @Override + public boolean retainAll(final Collection coll) { + if (parent.isEmpty()) { + return false; + } + if (coll.isEmpty()) { + parent.clear(); + return true; + } + boolean modified = false; + final Iterator it = iterator(); + while (it.hasNext()) { + if (coll.contains(it.next()) == false) { + it.remove(); + modified = true; + } + } + return modified; + } + + @Override + public void clear() { + parent.clear(); + } + } + + //----------------------------------------------------------------------- + /** + * Inner class KeySet. + */ + protected static class KeySet extends View implements Set { + + /** Serialization version */ + private static final long serialVersionUID = -7107935777385040694L; + + /** + * Constructs a new view of the BidiMap. + * + * @param parent the parent BidiMap + */ + @SuppressWarnings("unchecked") + protected KeySet(final AbstractDualBidiMap parent) { + super(parent.normalMap.keySet(), (AbstractDualBidiMap) parent); + } + + @Override + public Iterator iterator() { + return parent.createKeySetIterator(super.iterator()); + } + + @Override + public boolean contains(final Object key) { + return parent.normalMap.containsKey(key); + } + + @Override + public boolean remove(final Object key) { + if (parent.normalMap.containsKey(key)) { + final Object value = parent.normalMap.remove(key); + parent.reverseMap.remove(value); + return true; + } + return false; + } + } + + /** + * Inner class KeySetIterator. + */ + protected static class KeySetIterator extends AbstractIteratorDecorator { + + /** The parent map */ + protected final AbstractDualBidiMap parent; + + /** The last returned key */ + protected K lastKey = null; + + /** Whether remove is allowed at present */ + protected boolean canRemove = false; + + /** + * Constructor. + * @param iterator the iterator to decorate + * @param parent the parent map + */ + protected KeySetIterator(final Iterator iterator, final AbstractDualBidiMap parent) { + super(iterator); + this.parent = parent; + } + + @Override + public K next() { + lastKey = super.next(); + canRemove = true; + return lastKey; + } + + @Override + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + final Object value = parent.normalMap.get(lastKey); + super.remove(); + parent.reverseMap.remove(value); + lastKey = null; + canRemove = false; + } + } + + //----------------------------------------------------------------------- + /** + * Inner class Values. + */ + protected static class Values extends View implements Set { + + /** Serialization version */ + private static final long serialVersionUID = 4023777119829639864L; + + /** + * Constructs a new view of the BidiMap. + * + * @param parent the parent BidiMap + */ + @SuppressWarnings("unchecked") + protected Values(final AbstractDualBidiMap parent) { + super(parent.normalMap.values(), (AbstractDualBidiMap) parent); + } + + @Override + public Iterator iterator() { + return parent.createValuesIterator(super.iterator()); + } + + @Override + public boolean contains(final Object value) { + return parent.reverseMap.containsKey(value); + } + + @Override + public boolean remove(final Object value) { + if (parent.reverseMap.containsKey(value)) { + final Object key = parent.reverseMap.remove(value); + parent.normalMap.remove(key); + return true; + } + return false; + } + } + + /** + * Inner class ValuesIterator. + */ + protected static class ValuesIterator extends AbstractIteratorDecorator { + + /** The parent map */ + protected final AbstractDualBidiMap parent; + + /** The last returned value */ + protected V lastValue = null; + + /** Whether remove is allowed at present */ + protected boolean canRemove = false; + + /** + * Constructor. + * @param iterator the iterator to decorate + * @param parent the parent map + */ + @SuppressWarnings("unchecked") + protected ValuesIterator(final Iterator iterator, final AbstractDualBidiMap parent) { + super(iterator); + this.parent = (AbstractDualBidiMap) parent; + } + + @Override + public V next() { + lastValue = super.next(); + canRemove = true; + return lastValue; + } + + @Override + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + super.remove(); // removes from maps[0] + parent.reverseMap.remove(lastValue); + lastValue = null; + canRemove = false; + } + } + + //----------------------------------------------------------------------- + /** + * Inner class EntrySet. + */ + protected static class EntrySet extends View> implements Set> { + + /** Serialization version */ + private static final long serialVersionUID = 4040410962603292348L; + + /** + * Constructs a new view of the BidiMap. + * + * @param parent the parent BidiMap + */ + protected EntrySet(final AbstractDualBidiMap parent) { + super(parent.normalMap.entrySet(), parent); + } + + @Override + public Iterator> iterator() { + return parent.createEntrySetIterator(super.iterator()); + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + final Object key = entry.getKey(); + if (parent.containsKey(key)) { + final V value = parent.normalMap.get(key); + if (value == null ? entry.getValue() == null : value.equals(entry.getValue())) { + parent.normalMap.remove(key); + parent.reverseMap.remove(value); + return true; + } + } + return false; + } + } + + /** + * Inner class EntrySetIterator. + */ + protected static class EntrySetIterator extends AbstractIteratorDecorator> { + + /** The parent map */ + protected final AbstractDualBidiMap parent; + + /** The last returned entry */ + protected Map.Entry last = null; + + /** Whether remove is allowed at present */ + protected boolean canRemove = false; + + /** + * Constructor. + * @param iterator the iterator to decorate + * @param parent the parent map + */ + protected EntrySetIterator(final Iterator> iterator, final AbstractDualBidiMap parent) { + super(iterator); + this.parent = parent; + } + + @Override + public Map.Entry next() { + last = new MapEntry(super.next(), parent); + canRemove = true; + return last; + } + + @Override + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + // store value as remove may change the entry in the decorator (eg.TreeMap) + final Object value = last.getValue(); + super.remove(); + parent.reverseMap.remove(value); + last = null; + canRemove = false; + } + } + + /** + * Inner class MapEntry. + */ + protected static class MapEntry extends AbstractMapEntryDecorator { + + /** The parent map */ + protected final AbstractDualBidiMap parent; + + /** + * Constructor. + * @param entry the entry to decorate + * @param parent the parent map + */ + protected MapEntry(final Map.Entry entry, final AbstractDualBidiMap parent) { + super(entry); + this.parent = parent; + } + + @Override + public V setValue(final V value) { + final K key = MapEntry.this.getKey(); + if (parent.reverseMap.containsKey(value) && + parent.reverseMap.get(value) != key) { + throw new IllegalArgumentException( + "Cannot use setValue() when the object being set is already in the map"); + } + parent.put(key, value); + return super.setValue(value); + } + } + + /** + * Inner class MapIterator. + */ + protected static class BidiMapIterator implements MapIterator, ResettableIterator { + + /** The parent map */ + protected final AbstractDualBidiMap parent; + + /** The iterator being wrapped */ + protected Iterator> iterator; + + /** The last returned entry */ + protected Map.Entry last = null; + + /** Whether remove is allowed at present */ + protected boolean canRemove = false; + + /** + * Constructor. + * @param parent the parent map + */ + protected BidiMapIterator(final AbstractDualBidiMap parent) { + super(); + this.parent = parent; + this.iterator = parent.normalMap.entrySet().iterator(); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public K next() { + last = iterator.next(); + canRemove = true; + return last.getKey(); + } + + @Override + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + // store value as remove may change the entry in the decorator (eg.TreeMap) + final V value = last.getValue(); + iterator.remove(); + parent.reverseMap.remove(value); + last = null; + canRemove = false; + } + + @Override + public K getKey() { + if (last == null) { + throw new IllegalStateException( + "Iterator getKey() can only be called after next() and before remove()"); + } + return last.getKey(); + } + + @Override + public V getValue() { + if (last == null) { + throw new IllegalStateException( + "Iterator getValue() can only be called after next() and before remove()"); + } + return last.getValue(); + } + + @Override + public V setValue(final V value) { + if (last == null) { + throw new IllegalStateException( + "Iterator setValue() can only be called after next() and before remove()"); + } + if (parent.reverseMap.containsKey(value) && + parent.reverseMap.get(value) != last.getKey()) { + throw new IllegalArgumentException( + "Cannot use setValue() when the object being set is already in the map"); + } + return parent.put(last.getKey(), value); + } + + @Override + public void reset() { + iterator = parent.normalMap.entrySet().iterator(); + last = null; + canRemove = false; + } + + @Override + public String toString() { + if (last != null) { + return "MapIterator[" + getKey() + "=" + getValue() + "]"; + } + return "MapIterator[]"; + } + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/AbstractOrderedBidiMapDecorator.java b/src/org/apache/commons/collections4/bidimap/AbstractOrderedBidiMapDecorator.java new file mode 100644 index 0000000..ef7823f --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/AbstractOrderedBidiMapDecorator.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import org.apache.commons.collections4.OrderedBidiMap; +import org.apache.commons.collections4.OrderedMapIterator; + +/** + * Provides a base decorator that enables additional functionality to be added + * to an OrderedBidiMap via decoration. + *

          + * Methods are forwarded directly to the decorated map. + *

          + * This implementation does not perform any special processing with the map views. + * Instead it simply returns the inverse from the wrapped map. This may be + * undesirable, for example if you are trying to write a validating implementation + * it would provide a loophole around the validation. + * But, you might want that loophole, so this class is kept simple. + * + * @since 3.0 + * @version $Id: AbstractOrderedBidiMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractOrderedBidiMapDecorator + extends AbstractBidiMapDecorator + implements OrderedBidiMap { + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if the collection is null + */ + protected AbstractOrderedBidiMapDecorator(final OrderedBidiMap map) { + super(map); + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + @Override + protected OrderedBidiMap decorated() { + return (OrderedBidiMap) super.decorated(); + } + + //----------------------------------------------------------------------- + @Override + public OrderedMapIterator mapIterator() { + return decorated().mapIterator(); + } + + @Override + public K firstKey() { + return decorated().firstKey(); + } + + @Override + public K lastKey() { + return decorated().lastKey(); + } + + @Override + public K nextKey(final K key) { + return decorated().nextKey(key); + } + + @Override + public K previousKey(final K key) { + return decorated().previousKey(key); + } + + @Override + public OrderedBidiMap inverseBidiMap() { + return decorated().inverseBidiMap(); + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/AbstractSortedBidiMapDecorator.java b/src/org/apache/commons/collections4/bidimap/AbstractSortedBidiMapDecorator.java new file mode 100644 index 0000000..f4195df --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/AbstractSortedBidiMapDecorator.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.util.Comparator; +import java.util.SortedMap; + +import org.apache.commons.collections4.SortedBidiMap; + +/** + * Provides a base decorator that enables additional functionality to be added + * to a SortedBidiMap via decoration. + *

          + * Methods are forwarded directly to the decorated map. + *

          + * This implementation does not perform any special processing with the map views. + * Instead it simply returns the inverse from the wrapped map. This may be + * undesirable, for example if you are trying to write a validating implementation + * it would provide a loophole around the validation. + * But, you might want that loophole, so this class is kept simple. + * + * @since 3.0 + * @version $Id: AbstractSortedBidiMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractSortedBidiMapDecorator + extends AbstractOrderedBidiMapDecorator implements SortedBidiMap { + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if the collection is null + */ + public AbstractSortedBidiMapDecorator(final SortedBidiMap map) { + super(map); + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + @Override + protected SortedBidiMap decorated() { + return (SortedBidiMap) super.decorated(); + } + + //----------------------------------------------------------------------- + @Override + public SortedBidiMap inverseBidiMap() { + return decorated().inverseBidiMap(); + } + + @Override + public Comparator comparator() { + return decorated().comparator(); + } + + @Override + public Comparator valueComparator() { + return decorated().valueComparator(); + } + + @Override + public SortedMap subMap(final K fromKey, final K toKey) { + return decorated().subMap(fromKey, toKey); + } + + @Override + public SortedMap headMap(final K toKey) { + return decorated().headMap(toKey); + } + + @Override + public SortedMap tailMap(final K fromKey) { + return decorated().tailMap(fromKey); + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/DualHashBidiMap.java b/src/org/apache/commons/collections4/bidimap/DualHashBidiMap.java new file mode 100644 index 0000000..3187ccd --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/DualHashBidiMap.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.collections4.BidiMap; + +/** + * Implementation of {@link BidiMap} that uses two {@link HashMap} instances. + *

          + * Two {@link HashMap} instances are used in this class. + * This provides fast lookups at the expense of storing two sets of map entries. + * Commons Collections would welcome the addition of a direct hash-based + * implementation of the {@link BidiMap} interface. + *

          + * NOTE: From Commons Collections 3.1, all subclasses will use {@link HashMap} + * and the flawed createMap method is ignored. + * + * @since 3.0 + * @version $Id: DualHashBidiMap.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public class DualHashBidiMap extends AbstractDualBidiMap implements Serializable { + + /** Ensure serialization compatibility */ + private static final long serialVersionUID = 721969328361808L; + + /** + * Creates an empty HashBidiMap. + */ + public DualHashBidiMap() { + super(new HashMap(), new HashMap()); + } + + /** + * Constructs a HashBidiMap and copies the mappings from + * specified Map. + * + * @param map the map whose mappings are to be placed in this map + */ + public DualHashBidiMap(final Map map) { + super(new HashMap(), new HashMap()); + putAll(map); + } + + /** + * Constructs a HashBidiMap that decorates the specified maps. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseBidiMap the inverse BidiMap + */ + protected DualHashBidiMap(final Map normalMap, final Map reverseMap, + final BidiMap inverseBidiMap) { + super(normalMap, reverseMap, inverseBidiMap); + } + + /** + * Creates a new instance of this object. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseBidiMap the inverse BidiMap + * @return new bidi map + */ + @Override + protected BidiMap createBidiMap(final Map normalMap, final Map reverseMap, + final BidiMap inverseBidiMap) { + return new DualHashBidiMap(normalMap, reverseMap, inverseBidiMap); + } + + // Serialization + //----------------------------------------------------------------------- + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(normalMap); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + normalMap = new HashMap(); + reverseMap = new HashMap(); + @SuppressWarnings("unchecked") // will fail at runtime if stream is incorrect + final Map map = (Map) in.readObject(); + putAll(map); + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/DualLinkedHashBidiMap.java b/src/org/apache/commons/collections4/bidimap/DualLinkedHashBidiMap.java new file mode 100644 index 0000000..0b77fbd --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/DualLinkedHashBidiMap.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.collections4.BidiMap; + +/** + * Implementation of BidiMap that uses two LinkedHashMap instances. + *

          + * Two LinkedHashMap instances are used in this class. + * This provides fast lookups at the expense of storing two sets of map entries and two linked lists. + * + * @version $Id: DualLinkedHashBidiMap.java 1533984 2013-10-20 21:12:51Z tn $ + * @since 4.0 + */ +public class DualLinkedHashBidiMap extends AbstractDualBidiMap implements Serializable { + + /** Ensure serialization compatibility */ + private static final long serialVersionUID = 721969328361810L; + + /** + * Creates an empty HashBidiMap. + */ + public DualLinkedHashBidiMap() { + super(new LinkedHashMap(), new LinkedHashMap()); + } + + /** + * Constructs a LinkedHashBidiMap and copies the mappings from + * specified Map. + * + * @param map the map whose mappings are to be placed in this map + */ + public DualLinkedHashBidiMap(final Map map) { + super(new LinkedHashMap(), new LinkedHashMap()); + putAll(map); + } + + /** + * Constructs a LinkedHashBidiMap that decorates the specified maps. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseBidiMap the inverse BidiMap + */ + protected DualLinkedHashBidiMap(final Map normalMap, final Map reverseMap, + final BidiMap inverseBidiMap) { + super(normalMap, reverseMap, inverseBidiMap); + } + + /** + * Creates a new instance of this object. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseBidiMap the inverse BidiMap + * @return new bidi map + */ + @Override + protected BidiMap createBidiMap(final Map normalMap, final Map reverseMap, + final BidiMap inverseBidiMap) { + return new DualLinkedHashBidiMap(normalMap, reverseMap, inverseBidiMap); + } + + // Serialization + //----------------------------------------------------------------------- + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(normalMap); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + normalMap = new LinkedHashMap(); + reverseMap = new LinkedHashMap(); + @SuppressWarnings("unchecked") // will fail at runtime if stream is incorrect + final Map map = (Map) in.readObject(); + putAll(map); + } +} diff --git a/src/org/apache/commons/collections4/bidimap/DualTreeBidiMap.java b/src/org/apache/commons/collections4/bidimap/DualTreeBidiMap.java new file mode 100644 index 0000000..f1872c1 --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/DualTreeBidiMap.java @@ -0,0 +1,416 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.OrderedBidiMap; +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.ResettableIterator; +import org.apache.commons.collections4.SortedBidiMap; +import org.apache.commons.collections4.map.AbstractSortedMapDecorator; + +/** + * Implementation of {@link BidiMap} that uses two {@link TreeMap} instances. + *

          + * The setValue() method on iterators will succeed only if the new value being set is + * not already in the bidimap. + *

          + * When considering whether to use this class, the {@link TreeBidiMap} class should + * also be considered. It implements the interface using a dedicated design, and does + * not store each object twice, which can save on memory use. + *

          + * NOTE: From Commons Collections 3.1, all subclasses will use {@link TreeMap} + * and the flawed createMap method is ignored. + * + * @since 3.0 + * @version $Id: DualTreeBidiMap.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public class DualTreeBidiMap extends AbstractDualBidiMap + implements SortedBidiMap, Serializable { + + /** Ensure serialization compatibility */ + private static final long serialVersionUID = 721969328361809L; + + /** The key comparator to use */ + private final Comparator comparator; + + /** The value comparator to use */ + private final Comparator valueComparator; + + /** + * Creates an empty DualTreeBidiMap + */ + public DualTreeBidiMap() { + super(new TreeMap(), new TreeMap()); + this.comparator = null; + this.valueComparator = null; + } + + /** + * Constructs a DualTreeBidiMap and copies the mappings from + * specified Map. + * + * @param map the map whose mappings are to be placed in this map + */ + public DualTreeBidiMap(final Map map) { + super(new TreeMap(), new TreeMap()); + putAll(map); + this.comparator = null; + this.valueComparator = null; + } + + /** + * Constructs a {@link DualTreeBidiMap} using the specified {@link Comparator}. + * + * @param keyComparator the comparator + * @param valueComparator the values comparator to use + */ + public DualTreeBidiMap(final Comparator keyComparator, final Comparator valueComparator) { + super(new TreeMap(keyComparator), new TreeMap(valueComparator)); + this.comparator = keyComparator; + this.valueComparator = valueComparator; + } + + /** + * Constructs a {@link DualTreeBidiMap} that decorates the specified maps. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseBidiMap the inverse BidiMap + */ + protected DualTreeBidiMap(final Map normalMap, final Map reverseMap, + final BidiMap inverseBidiMap) { + super(normalMap, reverseMap, inverseBidiMap); + this.comparator = ((SortedMap) normalMap).comparator(); + this.valueComparator = ((SortedMap) reverseMap).comparator(); + } + + /** + * Creates a new instance of this object. + * + * @param normalMap the normal direction map + * @param reverseMap the reverse direction map + * @param inverseMap the inverse BidiMap + * @return new bidi map + */ + @Override + protected DualTreeBidiMap createBidiMap(final Map normalMap, final Map reverseMap, + final BidiMap inverseMap) { + return new DualTreeBidiMap(normalMap, reverseMap, inverseMap); + } + + //----------------------------------------------------------------------- + + @Override + public Comparator comparator() { + return ((SortedMap) normalMap).comparator(); + } + + @Override + public Comparator valueComparator() { + return ((SortedMap) reverseMap).comparator(); + } + + @Override + public K firstKey() { + return ((SortedMap) normalMap).firstKey(); + } + + @Override + public K lastKey() { + return ((SortedMap) normalMap).lastKey(); + } + + @Override + public K nextKey(final K key) { + if (isEmpty()) { + return null; + } + if (normalMap instanceof OrderedMap) { + return ((OrderedMap) normalMap).nextKey(key); + } + final SortedMap sm = (SortedMap) normalMap; + final Iterator it = sm.tailMap(key).keySet().iterator(); + it.next(); + if (it.hasNext()) { + return it.next(); + } + return null; + } + + @Override + public K previousKey(final K key) { + if (isEmpty()) { + return null; + } + if (normalMap instanceof OrderedMap) { + return ((OrderedMap) normalMap).previousKey(key); + } + final SortedMap sm = (SortedMap) normalMap; + final SortedMap hm = sm.headMap(key); + if (hm.isEmpty()) { + return null; + } + return hm.lastKey(); + } + + //----------------------------------------------------------------------- + /** + * Obtains an ordered map iterator. + *

          + * This implementation copies the elements to an ArrayList in order to + * provide the forward/backward behaviour. + * + * @return a new ordered map iterator + */ + @Override + public OrderedMapIterator mapIterator() { + return new BidiOrderedMapIterator(this); + } + + public SortedBidiMap inverseSortedBidiMap() { + return inverseBidiMap(); + } + + public OrderedBidiMap inverseOrderedBidiMap() { + return inverseBidiMap(); + } + + //----------------------------------------------------------------------- + + @Override + public SortedMap headMap(final K toKey) { + final SortedMap sub = ((SortedMap) normalMap).headMap(toKey); + return new ViewMap(this, sub); + } + + @Override + public SortedMap tailMap(final K fromKey) { + final SortedMap sub = ((SortedMap) normalMap).tailMap(fromKey); + return new ViewMap(this, sub); + } + + @Override + public SortedMap subMap(final K fromKey, final K toKey) { + final SortedMap sub = ((SortedMap) normalMap).subMap(fromKey, toKey); + return new ViewMap(this, sub); + } + + @Override + public SortedBidiMap inverseBidiMap() { + return (SortedBidiMap) super.inverseBidiMap(); + } + + //----------------------------------------------------------------------- + /** + * Internal sorted map view. + */ + protected static class ViewMap extends AbstractSortedMapDecorator { + /** + * Constructor. + * @param bidi the parent bidi map + * @param sm the subMap sorted map + */ + protected ViewMap(final DualTreeBidiMap bidi, final SortedMap sm) { + // the implementation is not great here... + // use the normalMap as the filtered map, but reverseMap as the full map + // this forces containsValue and clear to be overridden + super(new DualTreeBidiMap(sm, bidi.reverseMap, bidi.inverseBidiMap)); + } + + @Override + public boolean containsValue(final Object value) { + // override as default implementation uses reverseMap + return decorated().normalMap.containsValue(value); + } + + @Override + public void clear() { + // override as default implementation uses reverseMap + for (final Iterator it = keySet().iterator(); it.hasNext();) { + it.next(); + it.remove(); + } + } + + @Override + public SortedMap headMap(final K toKey) { + return new ViewMap(decorated(), super.headMap(toKey)); + } + + @Override + public SortedMap tailMap(final K fromKey) { + return new ViewMap(decorated(), super.tailMap(fromKey)); + } + + @Override + public SortedMap subMap(final K fromKey, final K toKey) { + return new ViewMap(decorated(), super.subMap(fromKey, toKey)); + } + + @Override + protected DualTreeBidiMap decorated() { + return (DualTreeBidiMap) super.decorated(); + } + + @Override + public K previousKey(final K key) { + return decorated().previousKey(key); + } + + @Override + public K nextKey(final K key) { + return decorated().nextKey(key); + } + } + + //----------------------------------------------------------------------- + /** + * Inner class MapIterator. + */ + protected static class BidiOrderedMapIterator implements OrderedMapIterator, ResettableIterator { + + /** The parent map */ + private final AbstractDualBidiMap parent; + + /** The iterator being decorated */ + private ListIterator> iterator; + + /** The last returned entry */ + private Map.Entry last = null; + + /** + * Constructor. + * @param parent the parent map + */ + protected BidiOrderedMapIterator(final AbstractDualBidiMap parent) { + super(); + this.parent = parent; + iterator = new ArrayList>(parent.entrySet()).listIterator(); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public K next() { + last = iterator.next(); + return last.getKey(); + } + + @Override + public boolean hasPrevious() { + return iterator.hasPrevious(); + } + + @Override + public K previous() { + last = iterator.previous(); + return last.getKey(); + } + + @Override + public void remove() { + iterator.remove(); + parent.remove(last.getKey()); + last = null; + } + + @Override + public K getKey() { + if (last == null) { + throw new IllegalStateException( + "Iterator getKey() can only be called after next() and before remove()"); + } + return last.getKey(); + } + + @Override + public V getValue() { + if (last == null) { + throw new IllegalStateException( + "Iterator getValue() can only be called after next() and before remove()"); + } + return last.getValue(); + } + + @Override + public V setValue(final V value) { + if (last == null) { + throw new IllegalStateException( + "Iterator setValue() can only be called after next() and before remove()"); + } + if (parent.reverseMap.containsKey(value) && + parent.reverseMap.get(value) != last.getKey()) { + throw new IllegalArgumentException( + "Cannot use setValue() when the object being set is already in the map"); + } + final V oldValue = parent.put(last.getKey(), value); + // Map.Entry specifies that the behavior is undefined when the backing map + // has been modified (as we did with the put), so we also set the value + // (especially needed for IBM JDK) + last.setValue(value); + return oldValue; + } + + @Override + public void reset() { + iterator = new ArrayList>(parent.entrySet()).listIterator(); + last = null; + } + + @Override + public String toString() { + if (last != null) { + return "MapIterator[" + getKey() + "=" + getValue() + "]"; + } + return "MapIterator[]"; + } + } + + // Serialization + //----------------------------------------------------------------------- + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(normalMap); + } + + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + normalMap = new TreeMap(comparator); + reverseMap = new TreeMap(valueComparator); + @SuppressWarnings("unchecked") // will fail at runtime if the stream is incorrect + final Map map = (Map) in.readObject(); + putAll(map); + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/TreeBidiMap.java b/src/org/apache/commons/collections4/bidimap/TreeBidiMap.java new file mode 100644 index 0000000..8a517e2 --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/TreeBidiMap.java @@ -0,0 +1,2228 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import static org.apache.commons.collections4.bidimap.TreeBidiMap.DataElement.KEY; +import static org.apache.commons.collections4.bidimap.TreeBidiMap.DataElement.VALUE; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.AbstractSet; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.apache.commons.collections4.KeyValue; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.OrderedBidiMap; +import org.apache.commons.collections4.OrderedIterator; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator; +import org.apache.commons.collections4.keyvalue.UnmodifiableMapEntry; + +/** + * Red-Black tree-based implementation of BidiMap where all objects added + * implement the Comparable interface. + *

          + * This class guarantees that the map will be in both ascending key order + * and ascending value order, sorted according to the natural order for + * the key's and value's classes. + *

          + * This Map is intended for applications that need to be able to look + * up a key-value pairing by either key or value, and need to do so + * with equal efficiency. + *

          + * While that goal could be accomplished by taking a pair of TreeMaps + * and redirecting requests to the appropriate TreeMap (e.g., + * containsKey would be directed to the TreeMap that maps values to + * keys, containsValue would be directed to the TreeMap that maps keys + * to values), there are problems with that implementation. + * If the data contained in the TreeMaps is large, the cost of redundant + * storage becomes significant. The {@link DualTreeBidiMap} and + * {@link DualHashBidiMap} implementations use this approach. + *

          + * This solution keeps minimizes the data storage by holding data only once. + * The red-black algorithm is based on {@link java.util.TreeMap}, but has been modified + * to simultaneously map a tree node by key and by value. This doubles the + * cost of put operations (but so does using two TreeMaps), and nearly doubles + * the cost of remove operations (there is a savings in that the lookup of the + * node to be removed only has to be performed once). And since only one node + * contains the key and value, storage is significantly less than that + * required by two TreeMaps. + *

          + * The Map.Entry instances returned by the appropriate methods will + * not allow setValue() and will throw an + * UnsupportedOperationException on attempts to call that method. + * + * @since 3.0 (previously DoubleOrderedMap v2.0) + * @version $Id: TreeBidiMap.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public class TreeBidiMap, V extends Comparable> + implements OrderedBidiMap, Serializable { + + static enum DataElement { + KEY("key"), VALUE("value"); + + private final String description; + + /** + * Create a new TreeBidiMap.DataElement. + * + * @param description the description for the element + */ + private DataElement(final String description) { + this.description = description; + } + + @Override + public String toString() { + return description; + } + } + + private static final long serialVersionUID = 721969328361807L; + + private transient Node[] rootNode; + private transient int nodeCount = 0; + private transient int modifications = 0; + private transient Set keySet; + private transient Set valuesSet; + private transient Set> entrySet; + private transient Inverse inverse = null; + + //----------------------------------------------------------------------- + /** + * Constructs a new empty TreeBidiMap. + */ + @SuppressWarnings("unchecked") + public TreeBidiMap() { + super(); + rootNode = new Node[2]; + } + + /** + * Constructs a new TreeBidiMap by copying an existing Map. + * + * @param map the map to copy + * @throws ClassCastException if the keys/values in the map are + * not Comparable or are not mutually comparable + * @throws NullPointerException if any key or value in the map is null + */ + public TreeBidiMap(final Map map) { + this(); + putAll(map); + } + + //----------------------------------------------------------------------- + /** + * Returns the number of key-value mappings in this map. + * + * @return the number of key-value mappings in this map + */ + @Override + public int size() { + return nodeCount; + } + + /** + * Checks whether the map is empty or not. + * + * @return true if the map is empty + */ + @Override + public boolean isEmpty() { + return nodeCount == 0; + } + + /** + * Checks whether this map contains the a mapping for the specified key. + *

          + * The key must implement Comparable. + * + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified key + * @throws ClassCastException if the key is of an inappropriate type + * @throws NullPointerException if the key is null + */ + @Override + public boolean containsKey(final Object key) { + checkKey(key); + return lookupKey(key) != null; + } + + /** + * Checks whether this map contains the a mapping for the specified value. + *

          + * The value must implement Comparable. + * + * @param value value whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified value + * @throws ClassCastException if the value is of an inappropriate type + * @throws NullPointerException if the value is null + */ + @Override + public boolean containsValue(final Object value) { + checkValue(value); + return lookupValue(value) != null; + } + + /** + * Gets the value to which this map maps the specified key. + * Returns null if the map contains no mapping for this key. + *

          + * The key must implement Comparable. + * + * @param key key whose associated value is to be returned + * @return the value to which this map maps the specified key, + * or null if the map contains no mapping for this key + * @throws ClassCastException if the key is of an inappropriate type + * @throws NullPointerException if the key is null + */ + @Override + public V get(final Object key) { + checkKey(key); + final Node node = lookupKey(key); + return node == null ? null : node.getValue(); + } + + /** + * Puts the key-value pair into the map, replacing any previous pair. + *

          + * When adding a key-value pair, the value may already exist in the map + * against a different key. That mapping is removed, to ensure that the + * value only occurs once in the inverse map. + *

          +     *  BidiMap map1 = new TreeBidiMap();
          +     *  map.put("A","B");  // contains A mapped to B, as per Map
          +     *  map.put("A","C");  // contains A mapped to C, as per Map
          +     *
          +     *  BidiMap map2 = new TreeBidiMap();
          +     *  map.put("A","B");  // contains A mapped to B, as per Map
          +     *  map.put("C","B");  // contains C mapped to B, key A is removed
          +     * 
          + *

          + * Both key and value must implement Comparable. + * + * @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 for the key + * @throws ClassCastException if the key is of an inappropriate type + * @throws NullPointerException if the key is null + */ + @Override + public V put(final K key, final V value) { + final V result = get(key); + doPut(key, value); + return result; + } + + /** + * Puts all the mappings from the specified map into this map. + *

          + * All keys and values must implement Comparable. + * + * @param map the map to copy from + */ + @Override + public void putAll(final Map map) { + for (final Map.Entry e : map.entrySet()) { + put(e.getKey(), e.getValue()); + } + } + + /** + * Removes the mapping for this key from this map if present. + *

          + * The key must implement Comparable. + * + * @param key key whose mapping is to be removed from the map. + * @return previous value associated with specified key, + * or null if there was no mapping for key. + * @throws ClassCastException if the key is of an inappropriate type + * @throws NullPointerException if the key is null + */ + @Override + public V remove(final Object key) { + return doRemoveKey(key); + } + + /** + * Removes all mappings from this map. + */ + @Override + public void clear() { + modify(); + + nodeCount = 0; + rootNode[KEY.ordinal()] = null; + rootNode[VALUE.ordinal()] = null; + } + + //----------------------------------------------------------------------- + /** + * Returns the key to which this map maps the specified value. + * Returns null if the map contains no mapping for this value. + *

          + * The value must implement Comparable. + * + * @param value value whose associated key is to be returned. + * @return the key to which this map maps the specified value, + * or null if the map contains no mapping for this value. + * @throws ClassCastException if the value is of an inappropriate type + * @throws NullPointerException if the value is null + */ + @Override + public K getKey(final Object value) { + checkValue(value); + final Node node = lookupValue(value); + return node == null ? null : node.getKey(); + } + + /** + * Removes the mapping for this value from this map if present. + *

          + * The value must implement Comparable. + * + * @param value value whose mapping is to be removed from the map + * @return previous key associated with specified value, + * or null if there was no mapping for value. + * @throws ClassCastException if the value is of an inappropriate type + * @throws NullPointerException if the value is null + */ + @Override + public K removeValue(final Object value) { + return doRemoveValue(value); + } + + //----------------------------------------------------------------------- + /** + * Gets the first (lowest) key currently in this map. + * + * @return the first (lowest) key currently in this sorted map + * @throws NoSuchElementException if this map is empty + */ + @Override + public K firstKey() { + if (nodeCount == 0) { + throw new NoSuchElementException("Map is empty"); + } + return leastNode(rootNode[KEY.ordinal()], KEY).getKey(); + } + + /** + * Gets the last (highest) key currently in this map. + * + * @return the last (highest) key currently in this sorted map + * @throws NoSuchElementException if this map is empty + */ + @Override + public K lastKey() { + if (nodeCount == 0) { + throw new NoSuchElementException("Map is empty"); + } + return greatestNode(rootNode[KEY.ordinal()], KEY).getKey(); + } + + /** + * Gets the next key after the one specified. + *

          + * The key must implement Comparable. + * + * @param key the key to search for next from + * @return the next key, null if no match or at end + */ + @Override + public K nextKey(final K key) { + checkKey(key); + final Node node = nextGreater(lookupKey(key), KEY); + return node == null ? null : node.getKey(); + } + + /** + * Gets the previous key before the one specified. + *

          + * The key must implement Comparable. + * + * @param key the key to search for previous from + * @return the previous key, null if no match or at start + */ + @Override + public K previousKey(final K key) { + checkKey(key); + final Node node = nextSmaller(lookupKey(key), KEY); + return node == null ? null : node.getKey(); + } + + //----------------------------------------------------------------------- + /** + * Returns a set view of the keys contained in this map in 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, the results of the iteration are undefined. + *

          + * The set supports element removal, which removes the corresponding mapping + * from the map. It does not support the add or addAll operations. + * + * @return a set view of the keys contained in this map. + */ + @Override + public Set keySet() { + if (keySet == null) { + keySet = new KeyView(KEY); + } + return keySet; + } + + //----------------------------------------------------------------------- + /** + * Returns a set view of the values contained in this map in key order. + * The returned object can be cast to a Set. + *

          + * 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, the results of the iteration are undefined. + *

          + * The set supports element removal, which removes the corresponding mapping + * from the map. It does not support the add or addAll operations. + * + * @return a set view of the values contained in this map. + */ + @Override + public Set values() { + if (valuesSet == null) { + valuesSet = new ValueView(KEY); + } + return valuesSet; + } + + //----------------------------------------------------------------------- + /** + * Returns a set view of the entries contained in this map in key order. + * For simple iteration through the map, the MapIterator is quicker. + *

          + * 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, the results of the iteration are undefined. + *

          + * The set supports element removal, which removes the corresponding mapping + * from the map. It does not support the add or addAll operations. + * The returned MapEntry objects do not support setValue. + * + * @return a set view of the values contained in this map. + */ + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = new EntryView(); + } + return entrySet; + } + + //----------------------------------------------------------------------- + @Override + public OrderedMapIterator mapIterator() { + if (isEmpty()) { + return EmptyOrderedMapIterator.emptyOrderedMapIterator(); + } + return new ViewMapIterator(KEY); + } + + //----------------------------------------------------------------------- + /** + * Gets the inverse map for comparison. + * + * @return the inverse map + */ + @Override + public OrderedBidiMap inverseBidiMap() { + if (inverse == null) { + inverse = new Inverse(); + } + return inverse; + } + + //----------------------------------------------------------------------- + /** + * Compares for equals as per the API. + * + * @param obj the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object obj) { + return this.doEquals(obj, KEY); + } + + /** + * Gets the hash code value for this map as per the API. + * + * @return the hash code value for this map + */ + @Override + public int hashCode() { + return this.doHashCode(KEY); + } + + /** + * Returns a string version of this Map in standard format. + * + * @return a standard format string version of the map + */ + @Override + public String toString() { + return this.doToString(KEY); + } + + //----------------------------------------------------------------------- + /** + * Put logic. + * + * @param key the key, always the main map key + * @param value the value, always the main map value + */ + private void doPut(final K key, final V value) { + checkKeyAndValue(key, value); + + // store previous and remove previous mappings + doRemoveKey(key); + doRemoveValue(value); + + Node node = rootNode[KEY.ordinal()]; + if (node == null) { + // map is empty + final Node root = new Node(key, value); + rootNode[KEY.ordinal()] = root; + rootNode[VALUE.ordinal()] = root; + grow(); + + } else { + // add new mapping + while (true) { + final int cmp = compare(key, node.getKey()); + + if (cmp == 0) { + // shouldn't happen + throw new IllegalArgumentException("Cannot store a duplicate key (\"" + key + "\") in this Map"); + } else if (cmp < 0) { + if (node.getLeft(KEY) != null) { + node = node.getLeft(KEY); + } else { + final Node newNode = new Node(key, value); + + insertValue(newNode); + node.setLeft(newNode, KEY); + newNode.setParent(node, KEY); + doRedBlackInsert(newNode, KEY); + grow(); + + break; + } + } else { // cmp > 0 + if (node.getRight(KEY) != null) { + node = node.getRight(KEY); + } else { + final Node newNode = new Node(key, value); + + insertValue(newNode); + node.setRight(newNode, KEY); + newNode.setParent(node, KEY); + doRedBlackInsert(newNode, KEY); + grow(); + + break; + } + } + } + } + } + + private V doRemoveKey(final Object key) { + final Node node = lookupKey(key); + if (node == null) { + return null; + } + doRedBlackDelete(node); + return node.getValue(); + } + + private K doRemoveValue(final Object value) { + final Node node = lookupValue(value); + if (node == null) { + return null; + } + doRedBlackDelete(node); + return node.getKey(); + } + + /** + * do the actual lookup of a piece of data + * + * @param data the key or value to be looked up + * @param index the KEY or VALUE int + * @return the desired Node, or null if there is no mapping of the + * specified data + */ + @SuppressWarnings("unchecked") + private > Node lookup(final Object data, final DataElement dataElement) { + Node rval = null; + Node node = rootNode[dataElement.ordinal()]; + + while (node != null) { + final int cmp = compare((T) data, (T) node.getData(dataElement)); + if (cmp == 0) { + rval = node; + break; + } else { + node = cmp < 0 ? node.getLeft(dataElement) : node.getRight(dataElement); + } + } + + return rval; + } + + private Node lookupKey(final Object key) { + return this.lookup(key, KEY); + } + + private Node lookupValue(final Object value) { + return this.lookup(value, VALUE); + } + + /** + * get the next larger node from the specified node + * + * @param node the node to be searched from + * @param index the KEY or VALUE int + * @return the specified node + */ + private Node nextGreater(final Node node, final DataElement dataElement) { + Node rval; + if (node == null) { + rval = null; + } else if (node.getRight(dataElement) != null) { + // everything to the node's right is larger. The least of + // the right node's descendants is the next larger node + rval = leastNode(node.getRight(dataElement), dataElement); + } else { + // traverse up our ancestry until we find an ancestor that + // is null or one whose left child is our ancestor. If we + // find a null, then this node IS the largest node in the + // tree, and there is no greater node. Otherwise, we are + // the largest node in the subtree on that ancestor's left + // ... and that ancestor is the next greatest node + Node parent = node.getParent(dataElement); + Node child = node; + + while (parent != null && child == parent.getRight(dataElement)) { + child = parent; + parent = parent.getParent(dataElement); + } + rval = parent; + } + return rval; + } + + /** + * get the next larger node from the specified node + * + * @param node the node to be searched from + * @param index the KEY or VALUE int + * @return the specified node + */ + private Node nextSmaller(final Node node, final DataElement dataElement) { + Node rval; + if (node == null) { + rval = null; + } else if (node.getLeft(dataElement) != null) { + // everything to the node's left is smaller. The greatest of + // the left node's descendants is the next smaller node + rval = greatestNode(node.getLeft(dataElement), dataElement); + } else { + // traverse up our ancestry until we find an ancestor that + // is null or one whose right child is our ancestor. If we + // find a null, then this node IS the largest node in the + // tree, and there is no greater node. Otherwise, we are + // the largest node in the subtree on that ancestor's right + // ... and that ancestor is the next greatest node + Node parent = node.getParent(dataElement); + Node child = node; + + while (parent != null && child == parent.getLeft(dataElement)) { + child = parent; + parent = parent.getParent(dataElement); + } + rval = parent; + } + return rval; + } + + //----------------------------------------------------------------------- + + /** + * Compare two objects + * + * @param o1 the first object + * @param o2 the second object + * + * @return negative value if o1 < o2; 0 if o1 == o2; positive + * value if o1 > o2 + */ + private static > int compare(final T o1, final T o2) { + return o1.compareTo(o2); + } + + /** + * Find the least node from a given node. + * + * @param node the node from which we will start searching + * @param index the KEY or VALUE int + * @return the smallest node, from the specified node, in the + * specified mapping + */ + private Node leastNode(final Node node, final DataElement dataElement) { + Node rval = node; + if (rval != null) { + while (rval.getLeft(dataElement) != null) { + rval = rval.getLeft(dataElement); + } + } + return rval; + } + + /** + * Find the greatest node from a given node. + * + * @param node the node from which we will start searching + * @param index the KEY or VALUE int + * @return the greatest node, from the specified node + */ + private Node greatestNode(final Node node, final DataElement dataElement) { + Node rval = node; + if (rval != null) { + while (rval.getRight(dataElement) != null) { + rval = rval.getRight(dataElement); + } + } + return rval; + } + + /** + * copy the color from one node to another, dealing with the fact + * that one or both nodes may, in fact, be null + * + * @param from the node whose color we're copying; may be null + * @param to the node whose color we're changing; may be null + * @param index the KEY or VALUE int + */ + private void copyColor(final Node from, final Node to, final DataElement dataElement) { + if (to != null) { + if (from == null) { + // by default, make it black + to.setBlack(dataElement); + } else { + to.copyColor(from, dataElement); + } + } + } + + /** + * is the specified node red? if the node does not exist, no, it's + * black, thank you + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private static boolean isRed(final Node node, final DataElement dataElement) { + return node != null && node.isRed(dataElement); + } + + /** + * is the specified black red? if the node does not exist, sure, + * it's black, thank you + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private static boolean isBlack(final Node node, final DataElement dataElement) { + return node == null || node.isBlack(dataElement); + } + + /** + * force a node (if it exists) red + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private static void makeRed(final Node node, final DataElement dataElement) { + if (node != null) { + node.setRed(dataElement); + } + } + + /** + * force a node (if it exists) black + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private static void makeBlack(final Node node, final DataElement dataElement) { + if (node != null) { + node.setBlack(dataElement); + } + } + + /** + * get a node's grandparent. mind you, the node, its parent, or + * its grandparent may not exist. no problem + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private Node getGrandParent(final Node node, final DataElement dataElement) { + return getParent(getParent(node, dataElement), dataElement); + } + + /** + * get a node's parent. mind you, the node, or its parent, may not + * exist. no problem + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private Node getParent(final Node node, final DataElement dataElement) { + return node == null ? null : node.getParent(dataElement); + } + + /** + * get a node's right child. mind you, the node may not exist. no + * problem + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private Node getRightChild(final Node node, final DataElement dataElement) { + return node == null ? null : node.getRight(dataElement); + } + + /** + * get a node's left child. mind you, the node may not exist. no + * problem + * + * @param node the node (may be null) in question + * @param index the KEY or VALUE int + */ + private Node getLeftChild(final Node node, final DataElement dataElement) { + return node == null ? null : node.getLeft(dataElement); + } + + /** + * do a rotate left. standard fare in the world of balanced trees + * + * @param node the node to be rotated + * @param index the KEY or VALUE int + */ + private void rotateLeft(final Node node, final DataElement dataElement) { + final Node rightChild = node.getRight(dataElement); + node.setRight(rightChild.getLeft(dataElement), dataElement); + + if (rightChild.getLeft(dataElement) != null) { + rightChild.getLeft(dataElement).setParent(node, dataElement); + } + rightChild.setParent(node.getParent(dataElement), dataElement); + + if (node.getParent(dataElement) == null) { + // node was the root ... now its right child is the root + rootNode[dataElement.ordinal()] = rightChild; + } else if (node.getParent(dataElement).getLeft(dataElement) == node) { + node.getParent(dataElement).setLeft(rightChild, dataElement); + } else { + node.getParent(dataElement).setRight(rightChild, dataElement); + } + + rightChild.setLeft(node, dataElement); + node.setParent(rightChild, dataElement); + } + + /** + * do a rotate right. standard fare in the world of balanced trees + * + * @param node the node to be rotated + * @param index the KEY or VALUE int + */ + private void rotateRight(final Node node, final DataElement dataElement) { + final Node leftChild = node.getLeft(dataElement); + node.setLeft(leftChild.getRight(dataElement), dataElement); + if (leftChild.getRight(dataElement) != null) { + leftChild.getRight(dataElement).setParent(node, dataElement); + } + leftChild.setParent(node.getParent(dataElement), dataElement); + + if (node.getParent(dataElement) == null) { + // node was the root ... now its left child is the root + rootNode[dataElement.ordinal()] = leftChild; + } else if (node.getParent(dataElement).getRight(dataElement) == node) { + node.getParent(dataElement).setRight(leftChild, dataElement); + } else { + node.getParent(dataElement).setLeft(leftChild, dataElement); + } + + leftChild.setRight(node, dataElement); + node.setParent(leftChild, dataElement); + } + + /** + * complicated red-black insert stuff. Based on Sun's TreeMap + * implementation, though it's barely recognizable any more + * + * @param insertedNode the node to be inserted + * @param dataElement the KEY or VALUE int + */ + private void doRedBlackInsert(final Node insertedNode, final DataElement dataElement) { + Node currentNode = insertedNode; + makeRed(currentNode, dataElement); + + while (currentNode != null + && currentNode != rootNode[dataElement.ordinal()] + && isRed(currentNode.getParent(dataElement), dataElement)) { + if (currentNode.isLeftChild(dataElement)) { + final Node y = getRightChild(getGrandParent(currentNode, dataElement), dataElement); + + if (isRed(y, dataElement)) { + makeBlack(getParent(currentNode, dataElement), dataElement); + makeBlack(y, dataElement); + makeRed(getGrandParent(currentNode, dataElement), dataElement); + + currentNode = getGrandParent(currentNode, dataElement); + } else { + //dead code? + if (currentNode.isRightChild(dataElement)) { + currentNode = getParent(currentNode, dataElement); + + rotateLeft(currentNode, dataElement); + } + + makeBlack(getParent(currentNode, dataElement), dataElement); + makeRed(getGrandParent(currentNode, dataElement), dataElement); + + if (getGrandParent(currentNode, dataElement) != null) { + rotateRight(getGrandParent(currentNode, dataElement), dataElement); + } + } + } else { + + // just like clause above, except swap left for right + final Node y = getLeftChild(getGrandParent(currentNode, dataElement), dataElement); + + if (isRed(y, dataElement)) { + makeBlack(getParent(currentNode, dataElement), dataElement); + makeBlack(y, dataElement); + makeRed(getGrandParent(currentNode, dataElement), dataElement); + + currentNode = getGrandParent(currentNode, dataElement); + } else { + //dead code? + if (currentNode.isLeftChild(dataElement)) { + currentNode = getParent(currentNode, dataElement); + + rotateRight(currentNode, dataElement); + } + + makeBlack(getParent(currentNode, dataElement), dataElement); + makeRed(getGrandParent(currentNode, dataElement), dataElement); + + if (getGrandParent(currentNode, dataElement) != null) { + rotateLeft(getGrandParent(currentNode, dataElement), dataElement); + } + } + } + } + + makeBlack(rootNode[dataElement.ordinal()], dataElement); + } + + /** + * complicated red-black delete stuff. Based on Sun's TreeMap + * implementation, though it's barely recognizable any more + * + * @param deletedNode the node to be deleted + */ + private void doRedBlackDelete(final Node deletedNode) { + for (final DataElement dataElement : DataElement.values()) { + // if deleted node has both left and children, swap with + // the next greater node + if (deletedNode.getLeft(dataElement) != null && deletedNode.getRight(dataElement) != null) { + swapPosition(nextGreater(deletedNode, dataElement), deletedNode, dataElement); + } + + final Node replacement = deletedNode.getLeft(dataElement) != null ? + deletedNode.getLeft(dataElement) : deletedNode.getRight(dataElement); + + if (replacement != null) { + replacement.setParent(deletedNode.getParent(dataElement), dataElement); + + if (deletedNode.getParent(dataElement) == null) { + rootNode[dataElement.ordinal()] = replacement; + } else if (deletedNode == deletedNode.getParent(dataElement).getLeft(dataElement)) { + deletedNode.getParent(dataElement).setLeft(replacement, dataElement); + } else { + deletedNode.getParent(dataElement).setRight(replacement, dataElement); + } + + deletedNode.setLeft(null, dataElement); + deletedNode.setRight(null, dataElement); + deletedNode.setParent(null, dataElement); + + if (isBlack(deletedNode, dataElement)) { + doRedBlackDeleteFixup(replacement, dataElement); + } + } else { + + // replacement is null + if (deletedNode.getParent(dataElement) == null) { + + // empty tree + rootNode[dataElement.ordinal()] = null; + } else { + + // deleted node had no children + if (isBlack(deletedNode, dataElement)) { + doRedBlackDeleteFixup(deletedNode, dataElement); + } + + if (deletedNode.getParent(dataElement) != null) { + if (deletedNode == deletedNode.getParent(dataElement).getLeft(dataElement)) { + deletedNode.getParent(dataElement).setLeft(null, dataElement); + } else { + deletedNode.getParent(dataElement).setRight(null, dataElement); + } + + deletedNode.setParent(null, dataElement); + } + } + } + } + shrink(); + } + + /** + * complicated red-black delete stuff. Based on Sun's TreeMap + * implementation, though it's barely recognizable any more. This + * rebalances the tree (somewhat, as red-black trees are not + * perfectly balanced -- perfect balancing takes longer) + * + * @param replacementNode the node being replaced + * @param dataElement the KEY or VALUE int + */ + private void doRedBlackDeleteFixup(final Node replacementNode, final DataElement dataElement) { + Node currentNode = replacementNode; + + while (currentNode != rootNode[dataElement.ordinal()] && isBlack(currentNode, dataElement)) { + if (currentNode.isLeftChild(dataElement)) { + Node siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement); + + if (isRed(siblingNode, dataElement)) { + makeBlack(siblingNode, dataElement); + makeRed(getParent(currentNode, dataElement), dataElement); + rotateLeft(getParent(currentNode, dataElement), dataElement); + + siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement); + } + + if (isBlack(getLeftChild(siblingNode, dataElement), dataElement) + && isBlack(getRightChild(siblingNode, dataElement), dataElement)) { + makeRed(siblingNode, dataElement); + + currentNode = getParent(currentNode, dataElement); + } else { + if (isBlack(getRightChild(siblingNode, dataElement), dataElement)) { + makeBlack(getLeftChild(siblingNode, dataElement), dataElement); + makeRed(siblingNode, dataElement); + rotateRight(siblingNode, dataElement); + + siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement); + } + + copyColor(getParent(currentNode, dataElement), siblingNode, dataElement); + makeBlack(getParent(currentNode, dataElement), dataElement); + makeBlack(getRightChild(siblingNode, dataElement), dataElement); + rotateLeft(getParent(currentNode, dataElement), dataElement); + + currentNode = rootNode[dataElement.ordinal()]; + } + } else { + Node siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement); + + if (isRed(siblingNode, dataElement)) { + makeBlack(siblingNode, dataElement); + makeRed(getParent(currentNode, dataElement), dataElement); + rotateRight(getParent(currentNode, dataElement), dataElement); + + siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement); + } + + if (isBlack(getRightChild(siblingNode, dataElement), dataElement) + && isBlack(getLeftChild(siblingNode, dataElement), dataElement)) { + makeRed(siblingNode, dataElement); + + currentNode = getParent(currentNode, dataElement); + } else { + if (isBlack(getLeftChild(siblingNode, dataElement), dataElement)) { + makeBlack(getRightChild(siblingNode, dataElement), dataElement); + makeRed(siblingNode, dataElement); + rotateLeft(siblingNode, dataElement); + + siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement); + } + + copyColor(getParent(currentNode, dataElement), siblingNode, dataElement); + makeBlack(getParent(currentNode, dataElement), dataElement); + makeBlack(getLeftChild(siblingNode, dataElement), dataElement); + rotateRight(getParent(currentNode, dataElement), dataElement); + + currentNode = rootNode[dataElement.ordinal()]; + } + } + } + + makeBlack(currentNode, dataElement); + } + + /** + * swap two nodes (except for their content), taking care of + * special cases where one is the other's parent ... hey, it + * happens. + * + * @param x one node + * @param y another node + * @param dataElement the KEY or VALUE int + */ + private void swapPosition(final Node x, final Node y, final DataElement dataElement) { + // Save initial values. + final Node xFormerParent = x.getParent(dataElement); + final Node xFormerLeftChild = x.getLeft(dataElement); + final Node xFormerRightChild = x.getRight(dataElement); + final Node yFormerParent = y.getParent(dataElement); + final Node yFormerLeftChild = y.getLeft(dataElement); + final Node yFormerRightChild = y.getRight(dataElement); + final boolean xWasLeftChild = + x.getParent(dataElement) != null && x == x.getParent(dataElement).getLeft(dataElement); + final boolean yWasLeftChild = + y.getParent(dataElement) != null && y == y.getParent(dataElement).getLeft(dataElement); + + // Swap, handling special cases of one being the other's parent. + if (x == yFormerParent) { // x was y's parent + x.setParent(y, dataElement); + + if (yWasLeftChild) { + y.setLeft(x, dataElement); + y.setRight(xFormerRightChild, dataElement); + } else { + y.setRight(x, dataElement); + y.setLeft(xFormerLeftChild, dataElement); + } + } else { + x.setParent(yFormerParent, dataElement); + + if (yFormerParent != null) { + if (yWasLeftChild) { + yFormerParent.setLeft(x, dataElement); + } else { + yFormerParent.setRight(x, dataElement); + } + } + + y.setLeft(xFormerLeftChild, dataElement); + y.setRight(xFormerRightChild, dataElement); + } + + if (y == xFormerParent) { // y was x's parent + y.setParent(x, dataElement); + + if (xWasLeftChild) { + x.setLeft(y, dataElement); + x.setRight(yFormerRightChild, dataElement); + } else { + x.setRight(y, dataElement); + x.setLeft(yFormerLeftChild, dataElement); + } + } else { + y.setParent(xFormerParent, dataElement); + + if (xFormerParent != null) { + if (xWasLeftChild) { + xFormerParent.setLeft(y, dataElement); + } else { + xFormerParent.setRight(y, dataElement); + } + } + + x.setLeft(yFormerLeftChild, dataElement); + x.setRight(yFormerRightChild, dataElement); + } + + // Fix children's parent pointers + if (x.getLeft(dataElement) != null) { + x.getLeft(dataElement).setParent(x, dataElement); + } + + if (x.getRight(dataElement) != null) { + x.getRight(dataElement).setParent(x, dataElement); + } + + if (y.getLeft(dataElement) != null) { + y.getLeft(dataElement).setParent(y, dataElement); + } + + if (y.getRight(dataElement) != null) { + y.getRight(dataElement).setParent(y, dataElement); + } + + x.swapColors(y, dataElement); + + // Check if root changed + if (rootNode[dataElement.ordinal()] == x) { + rootNode[dataElement.ordinal()] = y; + } else if (rootNode[dataElement.ordinal()] == y) { + rootNode[dataElement.ordinal()] = x; + } + } + + /** + * check if an object is fit to be proper input ... has to be + * Comparable and non-null + * + * @param o the object being checked + * @param index the KEY or VALUE int (used to put the right word in the + * exception message) + * + * @throws NullPointerException if o is null + * @throws ClassCastException if o is not Comparable + */ + private static void checkNonNullComparable(final Object o, final DataElement dataElement) { + if (o == null) { + throw new NullPointerException(dataElement + " cannot be null"); + } + if (!(o instanceof Comparable)) { + throw new ClassCastException(dataElement + " must be Comparable"); + } + } + + /** + * check a key for validity (non-null and implements Comparable) + * + * @param key the key to be checked + * + * @throws NullPointerException if key is null + * @throws ClassCastException if key is not Comparable + */ + private static void checkKey(final Object key) { + checkNonNullComparable(key, KEY); + } + + /** + * check a value for validity (non-null and implements Comparable) + * + * @param value the value to be checked + * + * @throws NullPointerException if value is null + * @throws ClassCastException if value is not Comparable + */ + private static void checkValue(final Object value) { + checkNonNullComparable(value, VALUE); + } + + /** + * check a key and a value for validity (non-null and implements + * Comparable) + * + * @param key the key to be checked + * @param value the value to be checked + * + * @throws NullPointerException if key or value is null + * @throws ClassCastException if key or value is not Comparable + */ + private static void checkKeyAndValue(final Object key, final Object value) { + checkKey(key); + checkValue(value); + } + + /** + * increment the modification count -- used to check for + * concurrent modification of the map through the map and through + * an Iterator from one of its Set or Collection views + */ + private void modify() { + modifications++; + } + + /** + * bump up the size and note that the map has changed + */ + private void grow() { + modify(); + nodeCount++; + } + + /** + * decrement the size and note that the map has changed + */ + private void shrink() { + modify(); + nodeCount--; + } + + /** + * insert a node by its value + * + * @param newNode the node to be inserted + * + * @throws IllegalArgumentException if the node already exists + * in the value mapping + */ + private void insertValue(final Node newNode) throws IllegalArgumentException { + Node node = rootNode[VALUE.ordinal()]; + + while (true) { + final int cmp = compare(newNode.getValue(), node.getValue()); + + if (cmp == 0) { + throw new IllegalArgumentException( + "Cannot store a duplicate value (\"" + newNode.getData(VALUE) + "\") in this Map"); + } else if (cmp < 0) { + if (node.getLeft(VALUE) != null) { + node = node.getLeft(VALUE); + } else { + node.setLeft(newNode, VALUE); + newNode.setParent(node, VALUE); + doRedBlackInsert(newNode, VALUE); + + break; + } + } else { // cmp > 0 + if (node.getRight(VALUE) != null) { + node = node.getRight(VALUE); + } else { + node.setRight(newNode, VALUE); + newNode.setParent(node, VALUE); + doRedBlackInsert(newNode, VALUE); + + break; + } + } + } + } + + //----------------------------------------------------------------------- + /** + * Compares for equals as per the API. + * + * @param obj the object to compare to + * @param type the KEY or VALUE int + * @return true if equal + */ + private boolean doEquals(final Object obj, final DataElement dataElement) { + if (obj == this) { + return true; + } + if (obj instanceof Map == false) { + return false; + } + final Map other = (Map) obj; + if (other.size() != size()) { + return false; + } + + if (nodeCount > 0) { + try { + for (final MapIterator it = getMapIterator(dataElement); it.hasNext(); ) { + final Object key = it.next(); + final Object value = it.getValue(); + if (value.equals(other.get(key)) == false) { + return false; + } + } + } catch (final ClassCastException ex) { + return false; + } catch (final NullPointerException ex) { + return false; + } + } + return true; + } + + /** + * Gets the hash code value for this map as per the API. + * + * @param type the KEY or VALUE int + * @return the hash code value for this map + */ + private int doHashCode(final DataElement dataElement) { + int total = 0; + if (nodeCount > 0) { + for (final MapIterator it = getMapIterator(dataElement); it.hasNext(); ) { + final Object key = it.next(); + final Object value = it.getValue(); + total += key.hashCode() ^ value.hashCode(); + } + } + return total; + } + + /** + * Gets the string form of this map as per AbstractMap. + * + * @param type the KEY or VALUE int + * @return the string form of this map + */ + private String doToString(final DataElement dataElement) { + if (nodeCount == 0) { + return "{}"; + } + final StringBuilder buf = new StringBuilder(nodeCount * 32); + buf.append('{'); + final MapIterator it = getMapIterator(dataElement); + boolean hasNext = it.hasNext(); + while (hasNext) { + final Object key = it.next(); + final Object value = it.getValue(); + buf.append(key == this ? "(this Map)" : key) + .append('=') + .append(value == this ? "(this Map)" : value); + + hasNext = it.hasNext(); + if (hasNext) { + buf.append(", "); + } + } + + buf.append('}'); + return buf.toString(); + } + + private MapIterator getMapIterator(final DataElement dataElement) { + switch (dataElement) { + case KEY: + return new ViewMapIterator(KEY); + case VALUE: + return new InverseViewMapIterator(VALUE); + default: + throw new IllegalArgumentException(); + } + } + + /** + * Reads the content of the stream. + */ + @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect + private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException{ + stream.defaultReadObject(); + rootNode = new Node[2]; + int size = stream.readInt(); + for(int i = 0; i < size; i++){ + K k =(K) stream.readObject(); + V v =(V) stream.readObject(); + put(k, v); + } + } + + /** + * Writes the content to the stream for serialization. + */ + private void writeObject(final ObjectOutputStream stream) throws IOException{ + stream.defaultWriteObject(); + stream.writeInt(this.size()); + for (final Entry entry : entrySet()) { + stream.writeObject(entry.getKey()); + stream.writeObject(entry.getValue()); + } + } + + //----------------------------------------------------------------------- + /** + * A view of this map. + */ + abstract class View extends AbstractSet { + + /** Whether to return KEY or VALUE order. */ + final DataElement orderType; + + /** + * Constructor. + * @param orderType the KEY or VALUE int for the order + * @param main the main map + */ + View(final DataElement orderType) { + super(); + this.orderType = orderType; + } + + @Override + public int size() { + return TreeBidiMap.this.size(); + } + + @Override + public void clear() { + TreeBidiMap.this.clear(); + } + } + + class KeyView extends View { + + /** + * Create a new TreeBidiMap.KeyView. + */ + public KeyView(final DataElement orderType) { + super(orderType); + } + + @Override + public Iterator iterator() { + return new ViewMapIterator(orderType); + } + + @Override + public boolean contains(final Object obj) { + checkNonNullComparable(obj, KEY); + return lookupKey(obj) != null; + } + + @Override + public boolean remove(final Object o) { + return doRemoveKey(o) != null; + } + + } + + class ValueView extends View { + + /** + * Create a new TreeBidiMap.ValueView. + */ + public ValueView(final DataElement orderType) { + super(orderType); + } + + @Override + public Iterator iterator() { + return new InverseViewMapIterator(orderType); + } + + @Override + public boolean contains(final Object obj) { + checkNonNullComparable(obj, VALUE); + return lookupValue(obj) != null; + } + + @Override + public boolean remove(final Object o) { + return doRemoveValue(o) != null; + } + + } + + /** + * A view of this map. + */ + class EntryView extends View> { + + EntryView() { + super(KEY); + } + + @Override + public boolean contains(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + final Object value = entry.getValue(); + final Node node = lookupKey(entry.getKey()); + return node != null && node.getValue().equals(value); + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + final Object value = entry.getValue(); + final Node node = lookupKey(entry.getKey()); + if (node != null && node.getValue().equals(value)) { + doRedBlackDelete(node); + return true; + } + return false; + } + + @Override + public Iterator> iterator() { + return new ViewMapEntryIterator(); + } + } + + /** + * A view of this map. + */ + class InverseEntryView extends View> { + + InverseEntryView() { + super(VALUE); + } + + @Override + public boolean contains(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + final Object value = entry.getValue(); + final Node node = lookupValue(entry.getKey()); + return node != null && node.getKey().equals(value); + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + final Object value = entry.getValue(); + final Node node = lookupValue(entry.getKey()); + if (node != null && node.getKey().equals(value)) { + doRedBlackDelete(node); + return true; + } + return false; + } + + @Override + public Iterator> iterator() { + return new InverseViewMapEntryIterator(); + } + } + + //----------------------------------------------------------------------- + /** + * An iterator over the map. + */ + abstract class ViewIterator { + + /** Whether to return KEY or VALUE order. */ + private final DataElement orderType; + /** The last node returned by the iterator. */ + Node lastReturnedNode; + /** The next node to be returned by the iterator. */ + private Node nextNode; + /** The previous node in the sequence returned by the iterator. */ + private Node previousNode; + /** The modification count. */ + private int expectedModifications; + + /** + * Constructor. + * @param orderType the KEY or VALUE int for the order + * @param main the main map + */ + ViewIterator(final DataElement orderType) { + super(); + this.orderType = orderType; + expectedModifications = modifications; + nextNode = leastNode(rootNode[orderType.ordinal()], orderType); + lastReturnedNode = null; + previousNode = null; + } + + public final boolean hasNext() { + return nextNode != null; + } + + protected Node navigateNext() { + if (nextNode == null) { + throw new NoSuchElementException(); + } + if (modifications != expectedModifications) { + throw new ConcurrentModificationException(); + } + lastReturnedNode = nextNode; + previousNode = nextNode; + nextNode = nextGreater(nextNode, orderType); + return lastReturnedNode; + } + + public boolean hasPrevious() { + return previousNode != null; + } + + protected Node navigatePrevious() { + if (previousNode == null) { + throw new NoSuchElementException(); + } + if (modifications != expectedModifications) { + throw new ConcurrentModificationException(); + } + nextNode = lastReturnedNode; + if (nextNode == null) { + nextNode = nextGreater(previousNode, orderType); + } + lastReturnedNode = previousNode; + previousNode = nextSmaller(previousNode, orderType); + return lastReturnedNode; + } + + public final void remove() { + if (lastReturnedNode == null) { + throw new IllegalStateException(); + } + if (modifications != expectedModifications) { + throw new ConcurrentModificationException(); + } + doRedBlackDelete(lastReturnedNode); + expectedModifications++; + lastReturnedNode = null; + if (nextNode == null) { + previousNode = greatestNode(rootNode[orderType.ordinal()], orderType); + } else { + previousNode = nextSmaller(nextNode, orderType); + } + } + } + + //----------------------------------------------------------------------- + /** + * An iterator over the map. + */ + class ViewMapIterator extends ViewIterator implements OrderedMapIterator { + + /** + * Constructor. + */ + ViewMapIterator(final DataElement orderType) { + super(orderType); + } + + @Override + public K getKey() { + if (lastReturnedNode == null) { + throw new IllegalStateException( + "Iterator getKey() can only be called after next() and before remove()"); + } + return lastReturnedNode.getKey(); + } + + @Override + public V getValue() { + if (lastReturnedNode == null) { + throw new IllegalStateException( + "Iterator getValue() can only be called after next() and before remove()"); + } + return lastReturnedNode.getValue(); + } + + @Override + public V setValue(final V obj) { + throw new UnsupportedOperationException(); + } + + @Override + public K next() { + return navigateNext().getKey(); + } + + @Override + public K previous() { + return navigatePrevious().getKey(); + } + } + + /** + * An iterator over the map. + */ + class InverseViewMapIterator extends ViewIterator implements OrderedMapIterator { + + /** + * Create a new TreeBidiMap.InverseViewMapIterator. + */ + public InverseViewMapIterator(final DataElement orderType) { + super(orderType); + } + + @Override + public V getKey() { + if (lastReturnedNode == null) { + throw new IllegalStateException( + "Iterator getKey() can only be called after next() and before remove()"); + } + return lastReturnedNode.getValue(); + } + + @Override + public K getValue() { + if (lastReturnedNode == null) { + throw new IllegalStateException( + "Iterator getValue() can only be called after next() and before remove()"); + } + return lastReturnedNode.getKey(); + } + + @Override + public K setValue(final K obj) { + throw new UnsupportedOperationException(); + } + + @Override + public V next() { + return navigateNext().getValue(); + } + + @Override + public V previous() { + return navigatePrevious().getValue(); + } + } + + /** + * An iterator over the map entries. + */ + class ViewMapEntryIterator extends ViewIterator implements OrderedIterator> { + + /** + * Constructor. + */ + ViewMapEntryIterator() { + super(KEY); + } + + @Override + public Map.Entry next() { + return navigateNext(); + } + + @Override + public Map.Entry previous() { + return navigatePrevious(); + } + } + + /** + * An iterator over the inverse map entries. + */ + class InverseViewMapEntryIterator extends ViewIterator implements OrderedIterator> { + + /** + * Constructor. + */ + InverseViewMapEntryIterator() { + super(VALUE); + } + + @Override + public Map.Entry next() { + return createEntry(navigateNext()); + } + + @Override + public Map.Entry previous() { + return createEntry(navigatePrevious()); + } + + private Map.Entry createEntry(final Node node) { + return new UnmodifiableMapEntry(node.getValue(), node.getKey()); + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + /** + * A node used to store the data. + */ + static class Node, V extends Comparable> implements Map.Entry, KeyValue { + + private final K key; + private final V value; + private final Node[] leftNode; + private final Node[] rightNode; + private final Node[] parentNode; + private final boolean[] blackColor; + private int hashcodeValue; + private boolean calculatedHashCode; + + /** + * Make a new cell with given key and value, and with null + * links, and black (true) colors. + * + * @param key + * @param value + */ + @SuppressWarnings("unchecked") + Node(final K key, final V value) { + super(); + this.key = key; + this.value = value; + leftNode = new Node[2]; + rightNode = new Node[2]; + parentNode = new Node[2]; + blackColor = new boolean[] { true, true }; + calculatedHashCode = false; + } + + private Object getData(final DataElement dataElement) { + switch (dataElement) { + case KEY: + return getKey(); + case VALUE: + return getValue(); + default: + throw new IllegalArgumentException(); + } + } + + private void setLeft(final Node node, final DataElement dataElement) { + leftNode[dataElement.ordinal()] = node; + } + + private Node getLeft(final DataElement dataElement) { + return leftNode[dataElement.ordinal()]; + } + + private void setRight(final Node node, final DataElement dataElement) { + rightNode[dataElement.ordinal()] = node; + } + + private Node getRight(final DataElement dataElement) { + return rightNode[dataElement.ordinal()]; + } + + /** + * Set this node's parent node. + * + * @param node the new parent node + * @param index the KEY or VALUE int + */ + private void setParent(final Node node, final DataElement dataElement) { + parentNode[dataElement.ordinal()] = node; + } + + /** + * Get the parent node. + * + * @param index the KEY or VALUE int + * @return the parent node, may be null + */ + private Node getParent(final DataElement dataElement) { + return parentNode[dataElement.ordinal()]; + } + + /** + * Exchange colors with another node. + * + * @param node the node to swap with + * @param index the KEY or VALUE int + */ + private void swapColors(final Node node, final DataElement dataElement) { + // Swap colors -- old hacker's trick + blackColor[dataElement.ordinal()] ^= node.blackColor[dataElement.ordinal()]; + node.blackColor[dataElement.ordinal()] ^= blackColor[dataElement.ordinal()]; + blackColor[dataElement.ordinal()] ^= node.blackColor[dataElement.ordinal()]; + } + + /** + * Is this node black? + * + * @param index the KEY or VALUE int + * @return true if black (which is represented as a true boolean) + */ + private boolean isBlack(final DataElement dataElement) { + return blackColor[dataElement.ordinal()]; + } + + /** + * Is this node red? + * + * @param index the KEY or VALUE int + * @return true if non-black + */ + private boolean isRed(final DataElement dataElement) { + return !blackColor[dataElement.ordinal()]; + } + + /** + * Make this node black. + * + * @param index the KEY or VALUE int + */ + private void setBlack(final DataElement dataElement) { + blackColor[dataElement.ordinal()] = true; + } + + /** + * Make this node red. + * + * @param index the KEY or VALUE int + */ + private void setRed(final DataElement dataElement) { + blackColor[dataElement.ordinal()] = false; + } + + /** + * Make this node the same color as another + * + * @param node the node whose color we're adopting + * @param index the KEY or VALUE int + */ + private void copyColor(final Node node, final DataElement dataElement) { + blackColor[dataElement.ordinal()] = node.blackColor[dataElement.ordinal()]; + } + + private boolean isLeftChild(final DataElement dataElement) { + return parentNode[dataElement.ordinal()] != null + && parentNode[dataElement.ordinal()].leftNode[dataElement.ordinal()] == this; + } + + private boolean isRightChild(final DataElement dataElement) { + return parentNode[dataElement.ordinal()] != null + && parentNode[dataElement.ordinal()].rightNode[dataElement.ordinal()] == this; + } + + //------------------------------------------------------------------- + /** + * Gets the key. + * + * @return the key corresponding to this entry. + */ + @Override + public K getKey() { + return key; + } + + /** + * Gets the value. + * + * @return the value corresponding to this entry. + */ + @Override + public V getValue() { + return value; + } + + /** + * Optional operation that is not permitted in this implementation + * + * @param ignored + * @return does not return + * @throws UnsupportedOperationException always + */ + @Override + public V setValue(final V ignored) throws UnsupportedOperationException { + throw new UnsupportedOperationException("Map.Entry.setValue is not supported"); + } + + /** + * Compares the specified object with this entry for equality. + * Returns true if the given object is also a map entry and + * the two entries represent the same mapping. + * + * @param obj the object to be compared for equality with this entry. + * @return true if the specified object is equal to this entry. + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Map.Entry)) { + return false; + } + final Map.Entry e = (Map.Entry) obj; + return getKey().equals(e.getKey()) && getValue().equals(e.getValue()); + } + + /** + * @return the hash code value for this map entry. + */ + @Override + public int hashCode() { + if (!calculatedHashCode) { + hashcodeValue = getKey().hashCode() ^ getValue().hashCode(); + calculatedHashCode = true; + } + return hashcodeValue; + } + } + + //----------------------------------------------------------------------- + /** + * The inverse map implementation. + */ + class Inverse implements OrderedBidiMap { + + /** Store the keySet once created. */ + private Set inverseKeySet; + /** Store the valuesSet once created. */ + private Set inverseValuesSet; + /** Store the entrySet once created. */ + private Set> inverseEntrySet; + + @Override + public int size() { + return TreeBidiMap.this.size(); + } + + @Override + public boolean isEmpty() { + return TreeBidiMap.this.isEmpty(); + } + + @Override + public K get(final Object key) { + return TreeBidiMap.this.getKey(key); + } + + @Override + public V getKey(final Object value) { + return TreeBidiMap.this.get(value); + } + + @Override + public boolean containsKey(final Object key) { + return TreeBidiMap.this.containsValue(key); + } + + @Override + public boolean containsValue(final Object value) { + return TreeBidiMap.this.containsKey(value); + } + + @Override + public V firstKey() { + if (TreeBidiMap.this.nodeCount == 0) { + throw new NoSuchElementException("Map is empty"); + } + return leastNode(TreeBidiMap.this.rootNode[VALUE.ordinal()], VALUE).getValue(); + } + + @Override + public V lastKey() { + if (TreeBidiMap.this.nodeCount == 0) { + throw new NoSuchElementException("Map is empty"); + } + return greatestNode(TreeBidiMap.this.rootNode[VALUE.ordinal()], VALUE).getValue(); + } + + @Override + public V nextKey(final V key) { + checkKey(key); + final Node node = nextGreater(TreeBidiMap.this.lookup(key, VALUE), VALUE); + return node == null ? null : node.getValue(); + } + + @Override + public V previousKey(final V key) { + checkKey(key); + final Node node = TreeBidiMap.this.nextSmaller(TreeBidiMap.this.lookup(key, VALUE), VALUE); + return node == null ? null : node.getValue(); + } + + @Override + public K put(final V key, final K value) { + final K result = get(key); + TreeBidiMap.this.doPut(value, key); + return result; + } + + @Override + public void putAll(final Map map) { + for (final Map.Entry e : map.entrySet()) { + put(e.getKey(), e.getValue()); + } + } + + @Override + public K remove(final Object key) { + return TreeBidiMap.this.removeValue(key); + } + + @Override + public V removeValue(final Object value) { + return TreeBidiMap.this.remove(value); + } + + @Override + public void clear() { + TreeBidiMap.this.clear(); + } + + @Override + public Set keySet() { + if (inverseKeySet == null) { + inverseKeySet = new ValueView(VALUE); + } + return inverseKeySet; + } + + @Override + public Set values() { + if (inverseValuesSet == null) { + inverseValuesSet = new KeyView(VALUE); + } + return inverseValuesSet; + } + + @Override + public Set> entrySet() { + if (inverseEntrySet == null) { + inverseEntrySet = new InverseEntryView(); + } + return inverseEntrySet; + } + + @Override + public OrderedMapIterator mapIterator() { + if (isEmpty()) { + return EmptyOrderedMapIterator.emptyOrderedMapIterator(); + } + return new InverseViewMapIterator(VALUE); + } + + @Override + public OrderedBidiMap inverseBidiMap() { + return TreeBidiMap.this; + } + + @Override + public boolean equals(final Object obj) { + return TreeBidiMap.this.doEquals(obj, DataElement.VALUE); + } + + @Override + public int hashCode() { + return TreeBidiMap.this.doHashCode(DataElement.VALUE); + } + + @Override + public String toString() { + return TreeBidiMap.this.doToString(DataElement.VALUE); + } + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/UnmodifiableBidiMap.java b/src/org/apache/commons/collections4/bidimap/UnmodifiableBidiMap.java new file mode 100644 index 0000000..29911fa --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/UnmodifiableBidiMap.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; +import org.apache.commons.collections4.map.UnmodifiableEntrySet; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another {@link BidiMap} to ensure it can't be altered. + *

          + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableBidiMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableBidiMap + extends AbstractBidiMapDecorator implements Unmodifiable { + + /** The inverse unmodifiable map */ + private UnmodifiableBidiMap inverse; + + /** + * Factory method to create an unmodifiable map. + *

          + * If the map passed in is already unmodifiable, it is returned. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return an unmodifiable BidiMap + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static BidiMap unmodifiableBidiMap(final BidiMap map) { + if (map instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final BidiMap tmpMap = (BidiMap) map; + return tmpMap; + } + return new UnmodifiableBidiMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableBidiMap(final BidiMap map) { + super((BidiMap) map); + } + + //----------------------------------------------------------------------- + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(final Map mapToCopy) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> entrySet() { + final Set> set = super.entrySet(); + return UnmodifiableEntrySet.unmodifiableEntrySet(set); + } + + @Override + public Set keySet() { + final Set set = super.keySet(); + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Set values() { + final Set set = super.values(); + return UnmodifiableSet.unmodifiableSet(set); + } + + //----------------------------------------------------------------------- + @Override + public K removeValue(final Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public MapIterator mapIterator() { + final MapIterator it = decorated().mapIterator(); + return UnmodifiableMapIterator.unmodifiableMapIterator(it); + } + + @Override + public synchronized BidiMap inverseBidiMap() { + if (inverse == null) { + inverse = new UnmodifiableBidiMap(decorated().inverseBidiMap()); + inverse.inverse = this; + } + return inverse; + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/UnmodifiableOrderedBidiMap.java b/src/org/apache/commons/collections4/bidimap/UnmodifiableOrderedBidiMap.java new file mode 100644 index 0000000..2b4397f --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/UnmodifiableOrderedBidiMap.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.OrderedBidiMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableOrderedMapIterator; +import org.apache.commons.collections4.map.UnmodifiableEntrySet; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another {@link OrderedBidiMap} to ensure it can't be altered. + *

          + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableOrderedBidiMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableOrderedBidiMap + extends AbstractOrderedBidiMapDecorator implements Unmodifiable { + + /** The inverse unmodifiable map */ + private UnmodifiableOrderedBidiMap inverse; + + /** + * Factory method to create an unmodifiable map. + *

          + * If the map passed in is already unmodifiable, it is returned. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return an unmodifiable OrderedBidiMap + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static OrderedBidiMap unmodifiableOrderedBidiMap( + final OrderedBidiMap map) { + if (map instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final OrderedBidiMap tmpMap = (OrderedBidiMap) map; + return tmpMap; + } + return new UnmodifiableOrderedBidiMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableOrderedBidiMap(final OrderedBidiMap map) { + super((OrderedBidiMap) map); + } + + //----------------------------------------------------------------------- + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(final Map mapToCopy) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> entrySet() { + final Set> set = super.entrySet(); + return UnmodifiableEntrySet.unmodifiableEntrySet(set); + } + + @Override + public Set keySet() { + final Set set = super.keySet(); + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Set values() { + final Set set = super.values(); + return UnmodifiableSet.unmodifiableSet(set); + } + + //----------------------------------------------------------------------- + @Override + public K removeValue(final Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public OrderedBidiMap inverseBidiMap() { + return inverseOrderedBidiMap(); + } + + //----------------------------------------------------------------------- + @Override + public OrderedMapIterator mapIterator() { + final OrderedMapIterator it = decorated().mapIterator(); + return UnmodifiableOrderedMapIterator.unmodifiableOrderedMapIterator(it); + } + + /** + * Gets an unmodifiable view of this map where the keys and values are reversed. + * + * @return an inverted unmodifiable bidirectional map + */ + public OrderedBidiMap inverseOrderedBidiMap() { + if (inverse == null) { + inverse = new UnmodifiableOrderedBidiMap(decorated().inverseBidiMap()); + inverse.inverse = this; + } + return inverse; + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/UnmodifiableSortedBidiMap.java b/src/org/apache/commons/collections4/bidimap/UnmodifiableSortedBidiMap.java new file mode 100644 index 0000000..c2f7955 --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/UnmodifiableSortedBidiMap.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.bidimap; + +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.SortedBidiMap; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableOrderedMapIterator; +import org.apache.commons.collections4.map.UnmodifiableEntrySet; +import org.apache.commons.collections4.map.UnmodifiableSortedMap; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another {@link SortedBidiMap} to ensure it can't be altered. + *

          + * Attempts to modify it will result in an {@link UnsupportedOperationException}. + * + * @since 3.0 + * @version $Id: UnmodifiableSortedBidiMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableSortedBidiMap + extends AbstractSortedBidiMapDecorator implements Unmodifiable { + + /** The inverse unmodifiable map */ + private UnmodifiableSortedBidiMap inverse; + + /** + * Factory method to create an unmodifiable map. + *

          + * If the map passed in is already unmodifiable, it is returned. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return an unmodifiable SortedBidiMap + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static SortedBidiMap unmodifiableSortedBidiMap(final SortedBidiMap map) { + if (map instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final SortedBidiMap tmpMap = (SortedBidiMap) map; + return tmpMap; + } + return new UnmodifiableSortedBidiMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableSortedBidiMap(final SortedBidiMap map) { + super((SortedBidiMap) map); + } + + //----------------------------------------------------------------------- + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(final Map mapToCopy) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> entrySet() { + final Set> set = super.entrySet(); + return UnmodifiableEntrySet.unmodifiableEntrySet(set); + } + + @Override + public Set keySet() { + final Set set = super.keySet(); + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Set values() { + final Set set = super.values(); + return UnmodifiableSet.unmodifiableSet(set); + } + + //----------------------------------------------------------------------- + @Override + public K removeValue(final Object value) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public OrderedMapIterator mapIterator() { + final OrderedMapIterator it = decorated().mapIterator(); + return UnmodifiableOrderedMapIterator.unmodifiableOrderedMapIterator(it); + } + + //----------------------------------------------------------------------- + @Override + public SortedBidiMap inverseBidiMap() { + if (inverse == null) { + inverse = new UnmodifiableSortedBidiMap(decorated().inverseBidiMap()); + inverse.inverse = this; + } + return inverse; + } + + @Override + public SortedMap subMap(final K fromKey, final K toKey) { + final SortedMap sm = decorated().subMap(fromKey, toKey); + return UnmodifiableSortedMap.unmodifiableSortedMap(sm); + } + + @Override + public SortedMap headMap(final K toKey) { + final SortedMap sm = decorated().headMap(toKey); + return UnmodifiableSortedMap.unmodifiableSortedMap(sm); + } + + @Override + public SortedMap tailMap(final K fromKey) { + final SortedMap sm = decorated().tailMap(fromKey); + return UnmodifiableSortedMap.unmodifiableSortedMap(sm); + } + +} diff --git a/src/org/apache/commons/collections4/bidimap/package-info.java b/src/org/apache/commons/collections4/bidimap/package-info.java new file mode 100644 index 0000000..1d70f6c --- /dev/null +++ b/src/org/apache/commons/collections4/bidimap/package-info.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the + * {@link org.apache.commons.collections4.BidiMap BidiMap}, + * {@link org.apache.commons.collections4.OrderedBidiMap OrderedBidiMap} and + * {@link org.apache.commons.collections4.SortedBidiMap SortedBidiMap} interfaces. + * A BidiMap is an extension to Map that allows keys and values to be looked up with equal ease. + * One example usage is a system communicating to a legacy datasource that must convert codes + * from the new format to the old format and vice versa. + *

          + * The following implementations are provided in the package: + *

            + *
          • DualHashBidiMap - uses two HashMaps to implement BidiMap + *
          • DualLinkedHashBidiMap - uses two LinkedHashMaps to implement BidiMap + *
          • DualTreeBidiMap - uses two TreeMaps to implement SortedBidiMap + *
          • TreeBidiMap - red-black tree implementation of OrderedBidiMap + *
          + *

          + * The following decorators are provided in the package: + *

            + *
          • Unmodifiable - ensures the map cannot be altered + *
          + * + * @version $Id: package-info.java 1477745 2013-04-30 18:08:32Z tn $ + */ +package org.apache.commons.collections4.bidimap; diff --git a/src/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java b/src/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java new file mode 100644 index 0000000..e980e22 --- /dev/null +++ b/src/org/apache/commons/collections4/collection/AbstractCollectionDecorator.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; + +/** + * Decorates another Collection to provide additional behaviour. + *

          + * Each method call made on this Collection is forwarded to the + * decorated Collection. This class is used as a framework on which + * to build to extensions such as synchronized and unmodifiable behaviour. The + * main advantage of decoration is that one decorator can wrap any implementation + * of Collection, whereas sub-classing requires a new class to be + * written for each implementation. + *

          + * This implementation does not perform any special processing with + * {@link #iterator()}. Instead it simply returns the value from the + * wrapped collection. This may be undesirable, for example if you are trying + * to write an unmodifiable implementation it might provide a loophole. + *

          + * This implementation does not forward the hashCode and equals methods through + * to the backing object, but relies on Object's implementation. This is necessary + * to preserve the symmetry of equals. Custom definitions of equality are usually + * based on an interface, such as Set or List, so that the implementation of equals + * can cast the object being tested for equality to the custom interface. + * AbstractCollectionDecorator does not implement such custom interfaces directly; + * they are implemented only in subclasses. Therefore, forwarding equals would break + * symmetry, as the forwarding object might consider itself equal to the object being + * tested, but the reverse could not be true. This behavior is consistent with the + * JDK's collection wrappers, such as {@link java.util.Collections#unmodifiableCollection(Collection)}. + * Use an interface-specific subclass of AbstractCollectionDecorator, such as + * AbstractListDecorator, to preserve equality behavior, or override equals directly. + * + * @param the type of the elements in the collection + * @since 3.0 + * @version $Id: AbstractCollectionDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractCollectionDecorator + implements Collection, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 6249888059822088500L; + + /** The collection being decorated */ + private Collection collection; + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractCollectionDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param coll the collection to decorate, must not be null + * @throws NullPointerException if the collection is null + */ + protected AbstractCollectionDecorator(final Collection coll) { + if (coll == null) { + throw new NullPointerException("Collection must not be null."); + } + this.collection = coll; + } + + /** + * Gets the collection being decorated. + * All access to the decorated collection goes via this method. + * + * @return the decorated collection + */ + protected Collection decorated() { + return collection; + } + + /** + * Sets the collection being decorated. + *

          + * NOTE: this method should only be used during deserialization + * + * @param coll the decorated collection + */ + protected void setCollection(final Collection coll) { + this.collection = coll; + } + + //----------------------------------------------------------------------- + + @Override + public boolean add(final E object) { + return decorated().add(object); + } + + @Override + public boolean addAll(final Collection coll) { + return decorated().addAll(coll); + } + + @Override + public void clear() { + decorated().clear(); + } + + @Override + public boolean contains(final Object object) { + return decorated().contains(object); + } + + @Override + public boolean isEmpty() { + return decorated().isEmpty(); + } + + @Override + public Iterator iterator() { + return decorated().iterator(); + } + + @Override + public boolean remove(final Object object) { + return decorated().remove(object); + } + + @Override + public int size() { + return decorated().size(); + } + + @Override + public Object[] toArray() { + return decorated().toArray(); + } + + @Override + public T[] toArray(final T[] object) { + return decorated().toArray(object); + } + + @Override + public boolean containsAll(final Collection coll) { + return decorated().containsAll(coll); + } + + @Override + public boolean removeAll(final Collection coll) { + return decorated().removeAll(coll); + } + + @Override + public boolean retainAll(final Collection coll) { + return decorated().retainAll(coll); + } + + @Override + public String toString() { + return decorated().toString(); + } + +} diff --git a/src/org/apache/commons/collections4/collection/CompositeCollection.java b/src/org/apache/commons/collections4/collection/CompositeCollection.java new file mode 100644 index 0000000..f58579d --- /dev/null +++ b/src/org/apache/commons/collections4/collection/CompositeCollection.java @@ -0,0 +1,482 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.collections4.iterators.EmptyIterator; +import org.apache.commons.collections4.iterators.IteratorChain; +import org.apache.commons.collections4.list.UnmodifiableList; + +/** + * Decorates a collection of other collections to provide a single unified view. + *

          + * Changes made to this collection will actually be made on the decorated collection. + * Add and remove operations require the use of a pluggable strategy. If no + * strategy is provided then add and remove are unsupported. + * + * @param the type of the elements in the collection + * @since 3.0 + * @version $Id: CompositeCollection.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public class CompositeCollection implements Collection, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 8417515734108306801L; + + /** CollectionMutator to handle changes to the collection */ + private CollectionMutator mutator; + + /** Collections in the composite */ + private final List> all = new ArrayList>(); + + /** + * Create an empty CompositeCollection. + */ + public CompositeCollection() { + super(); + } + + /** + * Create a Composite Collection with one collection. + * + * @param compositeCollection the Collection to be appended to the composite + */ + public CompositeCollection(final Collection compositeCollection) { + super(); + addComposited(compositeCollection); + } + + /** + * Create a Composite Collection with two collections. + * + * @param compositeCollection1 the Collection to be appended to the composite + * @param compositeCollection2 the Collection to be appended to the composite + */ + public CompositeCollection(final Collection compositeCollection1, + final Collection compositeCollection2) { + super(); + addComposited(compositeCollection1, compositeCollection2); + } + + /** + * Create a Composite Collection with an array of collections. + * + * @param compositeCollections the collections to composite + */ + @SafeVarargs + public CompositeCollection(final Collection... compositeCollections) { + super(); + addComposited(compositeCollections); + } + + //----------------------------------------------------------------------- + /** + * Gets the size of this composite collection. + *

          + * This implementation calls size() on each collection. + * + * @return total number of elements in all contained containers + */ + @Override + public int size() { + int size = 0; + for (final Collection item : all) { + size += item.size(); + } + return size; + } + + /** + * Checks whether this composite collection is empty. + *

          + * This implementation calls isEmpty() on each collection. + * + * @return true if all of the contained collections are empty + */ + @Override + public boolean isEmpty() { + for (final Collection item : all) { + if (item.isEmpty() == false) { + return false; + } + } + return true; + } + + /** + * Checks whether this composite collection contains the object. + *

          + * This implementation calls contains() on each collection. + * + * @param obj the object to search for + * @return true if obj is contained in any of the contained collections + */ + @Override + public boolean contains(final Object obj) { + for (final Collection item : all) { + if (item.contains(obj)) { + return true; + } + } + return false; + } + + /** + * Gets an iterator over all the collections in this composite. + *

          + * This implementation uses an IteratorChain. + * + * @return an IteratorChain instance which supports + * remove(). Iteration occurs over contained collections in + * the order they were added, but this behavior should not be relied upon. + * @see IteratorChain + */ + @Override + public Iterator iterator() { + if (all.isEmpty()) { + return EmptyIterator.emptyIterator(); + } + final IteratorChain chain = new IteratorChain(); + for (final Collection item : all) { + chain.addIterator(item.iterator()); + } + return chain; + } + + /** + * Returns an array containing all of the elements in this composite. + * + * @return an object array of all the elements in the collection + */ + @Override + public Object[] toArray() { + final Object[] result = new Object[size()]; + int i = 0; + for (final Iterator it = iterator(); it.hasNext(); i++) { + result[i] = it.next(); + } + return result; + } + + /** + * Returns an object array, populating the supplied array if possible. + * See Collection interface for full details. + * + * @param the type of the elements in the collection + * @param array the array to use, populating if possible + * @return an array of all the elements in the collection + */ + @Override + @SuppressWarnings("unchecked") + public T[] toArray(final T[] array) { + final int size = size(); + Object[] result = null; + if (array.length >= size) { + result = array; + } else { + result = (Object[]) Array.newInstance(array.getClass().getComponentType(), size); + } + + int offset = 0; + for (final Collection item : all) { + for (final E e : item) { + result[offset++] = e; + } + } + if (result.length > size) { + result[size] = null; + } + return (T[]) result; + } + + /** + * Adds an object to the collection, throwing UnsupportedOperationException + * unless a CollectionMutator strategy is specified. + * + * @param obj the object to add + * @return {@code true} if the collection was modified + * @throws UnsupportedOperationException if CollectionMutator hasn't been set + * @throws UnsupportedOperationException if add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + @Override + public boolean add(final E obj) { + if (mutator == null) { + throw new UnsupportedOperationException( + "add() is not supported on CompositeCollection without a CollectionMutator strategy"); + } + return mutator.add(this, all, obj); + } + + /** + * Removes an object from the collection, throwing UnsupportedOperationException + * unless a CollectionMutator strategy is specified. + * + * @param obj the object being removed + * @return true if the collection is changed + * @throws UnsupportedOperationException if removed is unsupported + * @throws ClassCastException if the object cannot be removed due to its type + * @throws NullPointerException if the object cannot be removed because its null + * @throws IllegalArgumentException if the object cannot be removed + */ + @Override + public boolean remove(final Object obj) { + if (mutator == null) { + throw new UnsupportedOperationException( + "remove() is not supported on CompositeCollection without a CollectionMutator strategy"); + } + return mutator.remove(this, all, obj); + } + + /** + * Checks whether this composite contains all the elements in the specified collection. + *

          + * This implementation calls contains() for each element in the + * specified collection. + * + * @param coll the collection to check for + * @return true if all elements contained + */ + @Override + public boolean containsAll(final Collection coll) { + for (final Object item : coll) { + if (contains(item) == false) { + return false; + } + } + return true; + } + + /** + * Adds a collection of elements to this collection, throwing + * UnsupportedOperationException unless a CollectionMutator strategy is specified. + * + * @param coll the collection to add + * @return true if the collection was modified + * @throws UnsupportedOperationException if CollectionMutator hasn't been set + * @throws UnsupportedOperationException if add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + @Override + public boolean addAll(final Collection coll) { + if (mutator == null) { + throw new UnsupportedOperationException( + "addAll() is not supported on CompositeCollection without a CollectionMutator strategy"); + } + return mutator.addAll(this, all, coll); + } + + /** + * Removes the elements in the specified collection from this composite collection. + *

          + * This implementation calls removeAll on each collection. + * + * @param coll the collection to remove + * @return true if the collection was modified + * @throws UnsupportedOperationException if removeAll is unsupported + */ + @Override + public boolean removeAll(final Collection coll) { + if (coll.size() == 0) { + return false; + } + boolean changed = false; + for (final Collection item : all) { + changed |= item.removeAll(coll); + } + return changed; + } + + /** + * Retains all the elements in the specified collection in this composite collection, + * removing all others. + *

          + * This implementation calls retainAll() on each collection. + * + * @param coll the collection to remove + * @return true if the collection was modified + * @throws UnsupportedOperationException if retainAll is unsupported + */ + @Override + public boolean retainAll(final Collection coll) { + boolean changed = false; + for (final Collection item : all) { + changed |= item.retainAll(coll); + } + return changed; + } + + /** + * Removes all of the elements from this collection . + *

          + * This implementation calls clear() on each collection. + * + * @throws UnsupportedOperationException if clear is unsupported + */ + @Override + public void clear() { + for (final Collection coll : all) { + coll.clear(); + } + } + + //----------------------------------------------------------------------- + /** + * Specify a CollectionMutator strategy instance to handle changes. + * + * @param mutator the mutator to use + */ + public void setMutator(final CollectionMutator mutator) { + this.mutator = mutator; + } + + /** + * Add these Collections to the list of collections in this composite + * + * @param compositeCollection the Collection to be appended to the composite + */ + public void addComposited(final Collection compositeCollection) { + all.add(compositeCollection); + } + + /** + * Add these Collections to the list of collections in this composite + * + * @param compositeCollection1 the Collection to be appended to the composite + * @param compositeCollection2 the Collection to be appended to the composite + */ + public void addComposited(final Collection compositeCollection1, + final Collection compositeCollection2) { + all.add(compositeCollection1); + all.add(compositeCollection2); + } + + /** + * Add these Collections to the list of collections in this composite + * + * @param compositeCollections the Collections to be appended to the composite + */ + public void addComposited(@SuppressWarnings("unchecked") final Collection... compositeCollections) { + all.addAll(Arrays.asList(compositeCollections)); + } + + /** + * Removes a collection from the those being decorated in this composite. + * + * @param coll collection to be removed + */ + public void removeComposited(final Collection coll) { + all.remove(coll); + } + + //----------------------------------------------------------------------- + /** + * Returns a new collection containing all of the elements + * + * @return A new ArrayList containing all of the elements in this composite. + * The new collection is not backed by this composite. + */ + public Collection toCollection() { + return new ArrayList(this); + } + + /** + * Gets the collections being decorated. + * + * @return Unmodifiable list of all collections in this composite. + */ + public List> getCollections() { + return UnmodifiableList.unmodifiableList(all); + } + + /** + * Get the collection mutator to be used for this CompositeCollection. + * @return CollectionMutator + */ + protected CollectionMutator getMutator() { + return mutator; + } + + //----------------------------------------------------------------------- + /** + * Pluggable strategy to handle changes to the composite. + * + * @param the element being held in the collection + */ + public interface CollectionMutator extends Serializable { + + /** + * Called when an object is to be added to the composite. + * + * @param composite the CompositeCollection being changed + * @param collections all of the Collection instances in this CompositeCollection + * @param obj the object being added + * @return true if the collection is changed + * @throws UnsupportedOperationException if add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + boolean add(CompositeCollection composite, List> collections, E obj); + + /** + * Called when a collection is to be added to the composite. + * + * @param composite the CompositeCollection being changed + * @param collections all of the Collection instances in this CompositeCollection + * @param coll the collection being added + * @return true if the collection is changed + * @throws UnsupportedOperationException if add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + boolean addAll(CompositeCollection composite, + List> collections, + Collection coll); + + /** + * Called when an object is to be removed to the composite. + * + * @param composite the CompositeCollection being changed + * @param collections all of the Collection instances in this CompositeCollection + * @param obj the object being removed + * @return true if the collection is changed + * @throws UnsupportedOperationException if removed is unsupported + * @throws ClassCastException if the object cannot be removed due to its type + * @throws NullPointerException if the object cannot be removed because its null + * @throws IllegalArgumentException if the object cannot be removed + */ + boolean remove(CompositeCollection composite, + List> collections, + Object obj); + + } + +} + diff --git a/src/org/apache/commons/collections4/collection/IndexedCollection.java b/src/org/apache/commons/collections4/collection/IndexedCollection.java new file mode 100644 index 0000000..2c6c189 --- /dev/null +++ b/src/org/apache/commons/collections4/collection/IndexedCollection.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.util.Collection; +import java.util.HashMap; + +import org.apache.commons.collections4.MultiMap; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.map.MultiValueMap; + +/** + * An IndexedCollection is a Map-like view onto a Collection. It accepts a + * keyTransformer to define how the keys are converted from the values. + *

          + * Modifications made to this decorator modify the index as well as the + * decorated {@link Collection}. However, modifications to the underlying + * {@link Collection} will not update the index and it will get out of sync. + *

          + * If modification of the decorated {@link Collection} is unavoidable, then a + * call to {@link #reindex()} will update the index to the current contents of + * the {@link Collection}. + * + * @param the type of object in the index. + * @param the type of object in the collection. + * + * @since 4.0 + * @version $Id: IndexedCollection.java 1683018 2015-06-01 22:41:31Z tn $ + */ +@SuppressWarnings("deprecation") +public class IndexedCollection extends AbstractCollectionDecorator { + + // TODO: replace with MultiValuedMap + + /** Serialization version */ + private static final long serialVersionUID = -5512610452568370038L; + + /** The {@link Transformer} for generating index keys. */ + private final Transformer keyTransformer; + + /** The map of indexes to collected objects. */ + private final MultiMap index; + + /** The uniqueness constraint for the index. */ + private final boolean uniqueIndex; + + /** + * Create an {@link IndexedCollection} for a unique index. + *

          + * If an element is added, which maps to an existing key, an {@link IllegalArgumentException} + * will be thrown. + * + * @param the index object type. + * @param the collection type. + * @param coll the decorated {@link Collection}. + * @param keyTransformer the {@link Transformer} for generating index keys. + * @return the created {@link IndexedCollection}. + */ + public static IndexedCollection uniqueIndexedCollection(final Collection coll, + final Transformer keyTransformer) { + return new IndexedCollection(coll, keyTransformer, + MultiValueMap.multiValueMap(new HashMap>()), + true); + } + + /** + * Create an {@link IndexedCollection} for a non-unique index. + * + * @param the index object type. + * @param the collection type. + * @param coll the decorated {@link Collection}. + * @param keyTransformer the {@link Transformer} for generating index keys. + * @return the created {@link IndexedCollection}. + */ + public static IndexedCollection nonUniqueIndexedCollection(final Collection coll, + final Transformer keyTransformer) { + return new IndexedCollection(coll, keyTransformer, + MultiValueMap.multiValueMap(new HashMap>()), + false); + } + + /** + * Create a {@link IndexedCollection}. + * + * @param coll decorated {@link Collection} + * @param keyTransformer {@link Transformer} for generating index keys + * @param map map to use as index + * @param uniqueIndex if the index shall enforce uniqueness of index keys + */ + public IndexedCollection(final Collection coll, final Transformer keyTransformer, + final MultiMap map, final boolean uniqueIndex) { + super(coll); + this.keyTransformer = keyTransformer; + this.index = map; + this.uniqueIndex = uniqueIndex; + reindex(); + } + + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if the object maps to an existing key and the index + * enforces a uniqueness constraint + */ + @Override + public boolean add(final C object) { + final boolean added = super.add(object); + if (added) { + addToIndex(object); + } + return added; + } + + @Override + public boolean addAll(final Collection coll) { + boolean changed = false; + for (final C c: coll) { + changed |= add(c); + } + return changed; + } + + @Override + public void clear() { + super.clear(); + index.clear(); + } + + /** + * {@inheritDoc} + *

          + * Note: uses the index for fast lookup + */ + @SuppressWarnings("unchecked") + @Override + public boolean contains(final Object object) { + return index.containsKey(keyTransformer.transform((C) object)); + } + + /** + * {@inheritDoc} + *

          + * Note: uses the index for fast lookup + */ + @Override + public boolean containsAll(final Collection coll) { + for (final Object o : coll) { + if (!contains(o)) { + return false; + } + } + return true; + } + + /** + * Get the element associated with the given key. + *

          + * In case of a non-unique index, this method will return the first + * value associated with the given key. To retrieve all elements associated + * with a key, use {@link #values(Object)}. + * + * @param key key to look up + * @return element found + * @see #values(Object) + */ + public C get(final K key) { + @SuppressWarnings("unchecked") // index is a MultiMap which returns a Collection + final Collection coll = (Collection) index.get(key); + return coll == null ? null : coll.iterator().next(); + } + + /** + * Get all elements associated with the given key. + * + * @param key key to look up + * @return a collection of elements found, or null if {@code contains(key) == false} + */ + @SuppressWarnings("unchecked") // index is a MultiMap which returns a Collection + public Collection values(final K key) { + return (Collection) index.get(key); + } + + /** + * Clears the index and re-indexes the entire decorated {@link Collection}. + */ + public void reindex() { + index.clear(); + for (final C c : decorated()) { + addToIndex(c); + } + } + + @SuppressWarnings("unchecked") + @Override + public boolean remove(final Object object) { + final boolean removed = super.remove(object); + if (removed) { + removeFromIndex((C) object); + } + return removed; + } + + @Override + public boolean removeAll(final Collection coll) { + boolean changed = false; + for (final Object o : coll) { + changed |= remove(o); + } + return changed; + } + + @Override + public boolean retainAll(final Collection coll) { + final boolean changed = super.retainAll(coll); + if (changed) { + reindex(); + } + return changed; + } + + //----------------------------------------------------------------------- + + /** + * Provides checking for adding the index. + * + * @param object the object to index + * @throws IllegalArgumentException if the object maps to an existing key and the index + * enforces a uniqueness constraint + */ + private void addToIndex(final C object) { + final K key = keyTransformer.transform(object); + if (uniqueIndex && index.containsKey(key)) { + throw new IllegalArgumentException("Duplicate key in uniquely indexed collection."); + } + index.put(key, object); + } + + /** + * Removes an object from the index. + * + * @param object the object to remove + */ + private void removeFromIndex(final C object) { + index.remove(keyTransformer.transform(object)); + } + +} diff --git a/src/org/apache/commons/collections4/collection/PredicatedCollection.java b/src/org/apache/commons/collections4/collection/PredicatedCollection.java new file mode 100644 index 0000000..f9d757f --- /dev/null +++ b/src/org/apache/commons/collections4/collection/PredicatedCollection.java @@ -0,0 +1,444 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +import org.apache.commons.collections4.Bag; +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.bag.HashBag; +import org.apache.commons.collections4.bag.PredicatedBag; +import org.apache.commons.collections4.functors.NotNullPredicate; +import org.apache.commons.collections4.list.PredicatedList; +import org.apache.commons.collections4.multiset.HashMultiSet; +import org.apache.commons.collections4.multiset.PredicatedMultiSet; +import org.apache.commons.collections4.queue.PredicatedQueue; +import org.apache.commons.collections4.set.PredicatedSet; + +/** + * Decorates another {@link Collection} to validate that additions + * match a specified predicate. + *

          + * This collection exists to provide validation for the decorated collection. + * It is normally created to decorate an empty collection. + * If an object cannot be added to the collection, an IllegalArgumentException is thrown. + *

          + * One usage would be to ensure that no null entries are added to the collection: + *

          + * Collection coll = PredicatedCollection.predicatedCollection(new ArrayList(), NotNullPredicate.INSTANCE);
          + * 
          + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @param the type of the elements in the collection + * @since 3.0 + * @version $Id: PredicatedCollection.java 1714484 2015-11-15 18:20:41Z tn $ + */ +public class PredicatedCollection extends AbstractCollectionDecorator { + + /** Serialization version */ + private static final long serialVersionUID = -5259182142076705162L; + + /** The predicate to use */ + protected final Predicate predicate; + + /** + * Returns a Builder with the given predicate. + * + * @param the element type + * @param predicate the predicate to use + * @return a new Builder for predicated collections + * @since 4.1 + */ + public static Builder builder(final Predicate predicate) { + return new Builder(predicate); + } + + /** + * Returns a Builder with a NotNullPredicate. + * + * @param the element type + * @return a new Builder for predicated collections that ignores null values. + * @since 4.1 + */ + public static Builder notNullBuilder() { + return new Builder(NotNullPredicate.notNullPredicate()); + } + + /** + * Factory method to create a predicated (validating) collection. + *

          + * If there are any elements already in the collection being decorated, they + * are validated. + * + * @param the type of the elements in the collection + * @param coll the collection to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated collection + * @throws NullPointerException if collection or predicate is null + * @throws IllegalArgumentException if the collection contains invalid elements + * @since 4.0 + */ + public static PredicatedCollection predicatedCollection(final Collection coll, + final Predicate predicate) { + return new PredicatedCollection(coll, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

          + * If there are any elements already in the collection being decorated, they + * are validated. + * + * @param coll the collection to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if collection or predicate is null + * @throws IllegalArgumentException if the collection contains invalid elements + */ + protected PredicatedCollection(final Collection coll, final Predicate predicate) { + super(coll); + if (predicate == null) { + throw new NullPointerException("Predicate must not be null."); + } + this.predicate = predicate; + for (final E item : coll) { + validate(item); + } + } + + /** + * Validates the object being added to ensure it matches the predicate. + *

          + * The predicate itself should not throw an exception, but return false to + * indicate that the object cannot be added. + * + * @param object the object being added + * @throws IllegalArgumentException if the add is invalid + */ + protected void validate(final E object) { + if (predicate.evaluate(object) == false) { + throw new IllegalArgumentException("Cannot add Object '" + object + "' - Predicate '" + + predicate + "' rejected it"); + } + } + + //----------------------------------------------------------------------- + /** + * Override to validate the object being added to ensure it matches + * the predicate. + * + * @param object the object being added + * @return the result of adding to the underlying collection + * @throws IllegalArgumentException if the add is invalid + */ + @Override + public boolean add(final E object) { + validate(object); + return decorated().add(object); + } + + /** + * Override to validate the objects being added to ensure they match + * the predicate. If any one fails, no update is made to the underlying + * collection. + * + * @param coll the collection being added + * @return the result of adding to the underlying collection + * @throws IllegalArgumentException if the add is invalid + */ + @Override + public boolean addAll(final Collection coll) { + for (final E item : coll) { + validate(item); + } + return decorated().addAll(coll); + } + + /** + * Builder for creating predicated collections. + *

          + * Create a Builder with a predicate to validate elements against, then add any elements + * to the builder. Elements that fail the predicate will be added to a rejected list. + * Finally create or decorate a collection using the createPredicated[List,Set,Bag,Queue] methods. + *

          + * An example: + *

          +     *   Predicate<String> predicate = NotNullPredicate.notNullPredicate();
          +     *   PredicatedCollectionBuilder<String> builder = PredicatedCollection.builder(predicate);
          +     *   builder.add("item1");
          +     *   builder.add(null);
          +     *   builder.add("item2");
          +     *   List<String> predicatedList = builder.createPredicatedList();
          +     * 
          + *

          + * At the end of the code fragment above predicatedList is protected by the predicate supplied + * to the builder and it contains item1 and item2. + *

          + * More elements can be added to the builder once a predicated collection has been created, + * but these elements will not be reflected in already created collections. + * + * @param the element type + * @since 4.1 + */ + public static class Builder { + + /** The predicate to use. */ + private final Predicate predicate; + + /** The buffer containing valid elements. */ + private final List accepted = new ArrayList(); + + /** The buffer containing rejected elements. */ + private final List rejected = new ArrayList(); + + // ----------------------------------------------------------------------- + /** + * Constructs a PredicatedCollectionBuilder with the specified Predicate. + * + * @param predicate the predicate to use + * @throws NullPointerException if predicate is null + */ + public Builder(final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + this.predicate = predicate; + } + + /** + * Adds the item to the builder. + *

          + * If the predicate is true, it is added to the list of accepted elements, + * otherwise it is added to the rejected list. + * + * @param item the element to add + * @return the PredicatedCollectionBuilder. + */ + public Builder add(final E item) { + if (predicate.evaluate(item)) { + accepted.add(item); + } else { + rejected.add(item); + } + return this; + } + + /** + * Adds all elements from the given collection to the builder. + *

          + * All elements for which the predicate evaluates to true will be added to the + * list of accepted elements, otherwise they are added to the rejected list. + * + * @param items the elements to add to the builder + * @return the PredicatedCollectionBuilder. + */ + public Builder addAll(final Collection items) { + if (items != null) { + for (E item : items) { + add(item); + } + } + return this; + } + + /** + * Create a new predicated list filled with the accepted elements. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned list. + * + * @return a new predicated list. + */ + public List createPredicatedList() { + return createPredicatedList(new ArrayList()); + } + + /** + * Decorates the given list with validating behavior using the predicate. All accepted elements + * are appended to the list. If the list already contains elements, they are validated. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned list. + * + * @param list the List to decorate, must not be null + * @return the decorated list. + * @throws NullPointerException if list is null + * @throws IllegalArgumentException if list contains invalid elements + */ + public List createPredicatedList(final List list) { + if (list == null) { + throw new NullPointerException("List must not be null."); + } + final List predicatedList = PredicatedList.predicatedList(list, predicate); + predicatedList.addAll(accepted); + return predicatedList; + } + + /** + * Create a new predicated set filled with the accepted elements. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned set. + * + * @return a new predicated set. + */ + public Set createPredicatedSet() { + return createPredicatedSet(new HashSet()); + } + + /** + * Decorates the given list with validating behavior using the predicate. All accepted elements + * are appended to the set. If the set already contains elements, they are validated. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned set. + * + * @param set the set to decorate, must not be null + * @return the decorated set. + * @throws NullPointerException if set is null + * @throws IllegalArgumentException if set contains invalid elements + */ + public Set createPredicatedSet(final Set set) { + if (set == null) { + throw new NullPointerException("Set must not be null."); + } + final PredicatedSet predicatedSet = PredicatedSet.predicatedSet(set, predicate); + predicatedSet.addAll(accepted); + return predicatedSet; + } + + /** + * Create a new predicated multiset filled with the accepted elements. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned multiset. + * + * @return a new predicated multiset. + */ + public MultiSet createPredicatedMultiSet() { + return createPredicatedMultiSet(new HashMultiSet()); + } + + /** + * Decorates the given multiset with validating behavior using the predicate. All accepted elements + * are appended to the multiset. If the multiset already contains elements, they are validated. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned multiset. + * + * @param multiset the multiset to decorate, must not be null + * @return the decorated multiset. + * @throws NullPointerException if multiset is null + * @throws IllegalArgumentException if multiset contains invalid elements + */ + public MultiSet createPredicatedMultiSet(final MultiSet multiset) { + if (multiset == null) { + throw new NullPointerException("MultiSet must not be null."); + } + final PredicatedMultiSet predicatedMultiSet = + PredicatedMultiSet.predicatedMultiSet(multiset, predicate); + predicatedMultiSet.addAll(accepted); + return predicatedMultiSet; + } + + /** + * Create a new predicated bag filled with the accepted elements. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned bag. + * + * @return a new predicated bag. + */ + public Bag createPredicatedBag() { + return createPredicatedBag(new HashBag()); + } + + /** + * Decorates the given bag with validating behavior using the predicate. All accepted elements + * are appended to the bag. If the bag already contains elements, they are validated. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned bag. + * + * @param bag the bag to decorate, must not be null + * @return the decorated bag. + * @throws NullPointerException if bag is null + * @throws IllegalArgumentException if bag contains invalid elements + */ + public Bag createPredicatedBag(final Bag bag) { + if (bag == null) { + throw new NullPointerException("Bag must not be null."); + } + final PredicatedBag predicatedBag = PredicatedBag.predicatedBag(bag, predicate); + predicatedBag.addAll(accepted); + return predicatedBag; + } + + /** + * Create a new predicated queue filled with the accepted elements. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned queue. + * + * @return a new predicated queue. + */ + public Queue createPredicatedQueue() { + return createPredicatedQueue(new LinkedList()); + } + + /** + * Decorates the given queue with validating behavior using the predicate. All accepted elements + * are appended to the queue. If the queue already contains elements, they are validated. + *

          + * The builder is not modified by this method, so it is possible to create more collections + * or add more elements afterwards. Further changes will not propagate to the returned queue. + * + * @param queue the queue to decorate, must not be null + * @return the decorated queue. + * @throws NullPointerException if queue is null + * @throws IllegalArgumentException if queue contains invalid elements + */ + public Queue createPredicatedQueue(final Queue queue) { + if (queue == null) { + throw new NullPointerException("queue must not be null"); + } + final PredicatedQueue predicatedQueue = PredicatedQueue.predicatedQueue(queue, predicate); + predicatedQueue.addAll(accepted); + return predicatedQueue; + } + + /** + * Returns an unmodifiable collection containing all rejected elements. + * + * @return an unmodifiable collection + */ + public Collection rejectedElements() { + return Collections.unmodifiableCollection(rejected); + } + + } + +} diff --git a/src/org/apache/commons/collections4/collection/SynchronizedCollection.java b/src/org/apache/commons/collections4/collection/SynchronizedCollection.java new file mode 100644 index 0000000..08cf956 --- /dev/null +++ b/src/org/apache/commons/collections4/collection/SynchronizedCollection.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; + +/** + * Decorates another {@link Collection} to synchronize its behaviour + * for a multi-threaded environment. + *

          + * Iterators must be manually synchronized: + *

          + * synchronized (coll) {
          + *   Iterator it = coll.iterator();
          + *   // do stuff with iterator
          + * }
          + * 
          + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @param the type of the elements in the collection + * @since 3.0 + * @version $Id: SynchronizedCollection.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class SynchronizedCollection implements Collection, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 2412805092710877986L; + + /** The collection to decorate */ + private final Collection collection; + /** The object to lock on, needed for List/SortedSet views */ + protected final Object lock; + + /** + * Factory method to create a synchronized collection. + * + * @param the type of the elements in the collection + * @param coll the collection to decorate, must not be null + * @return a new synchronized collection + * @throws NullPointerException if collection is null + * @since 4.0 + */ + public static SynchronizedCollection synchronizedCollection(final Collection coll) { + return new SynchronizedCollection(coll); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param collection the collection to decorate, must not be null + * @throws NullPointerException if the collection is null + */ + protected SynchronizedCollection(final Collection collection) { + if (collection == null) { + throw new NullPointerException("Collection must not be null."); + } + this.collection = collection; + this.lock = this; + } + + /** + * Constructor that wraps (not copies). + * + * @param collection the collection to decorate, must not be null + * @param lock the lock object to use, must not be null + * @throws NullPointerException if the collection or lock is null + */ + protected SynchronizedCollection(final Collection collection, final Object lock) { + if (collection == null) { + throw new NullPointerException("Collection must not be null."); + } + if (lock == null) { + throw new NullPointerException("Lock must not be null."); + } + this.collection = collection; + this.lock = lock; + } + + /** + * Gets the collection being decorated. + * + * @return the decorated collection + */ + protected Collection decorated() { + return collection; + } + + //----------------------------------------------------------------------- + + @Override + public boolean add(final E object) { + synchronized (lock) { + return decorated().add(object); + } + } + + @Override + public boolean addAll(final Collection coll) { + synchronized (lock) { + return decorated().addAll(coll); + } + } + + @Override + public void clear() { + synchronized (lock) { + decorated().clear(); + } + } + + @Override + public boolean contains(final Object object) { + synchronized (lock) { + return decorated().contains(object); + } + } + + @Override + public boolean containsAll(final Collection coll) { + synchronized (lock) { + return decorated().containsAll(coll); + } + } + + @Override + public boolean isEmpty() { + synchronized (lock) { + return decorated().isEmpty(); + } + } + + /** + * Iterators must be manually synchronized. + *

          +     * synchronized (coll) {
          +     *   Iterator it = coll.iterator();
          +     *   // do stuff with iterator
          +     * }
          +     * 
          + * + * @return an iterator that must be manually synchronized on the collection + */ + @Override + public Iterator iterator() { + return decorated().iterator(); + } + + @Override + public Object[] toArray() { + synchronized (lock) { + return decorated().toArray(); + } + } + + @Override + public T[] toArray(final T[] object) { + synchronized (lock) { + return decorated().toArray(object); + } + } + + @Override + public boolean remove(final Object object) { + synchronized (lock) { + return decorated().remove(object); + } + } + + @Override + public boolean removeAll(final Collection coll) { + synchronized (lock) { + return decorated().removeAll(coll); + } + } + + @Override + public boolean retainAll(final Collection coll) { + synchronized (lock) { + return decorated().retainAll(coll); + } + } + + @Override + public int size() { + synchronized (lock) { + return decorated().size(); + } + } + + @Override + public boolean equals(final Object object) { + synchronized (lock) { + if (object == this) { + return true; + } + return object == this || decorated().equals(object); + } + } + + @Override + public int hashCode() { + synchronized (lock) { + return decorated().hashCode(); + } + } + + @Override + public String toString() { + synchronized (lock) { + return decorated().toString(); + } + } + +} diff --git a/src/org/apache/commons/collections4/collection/TransformedCollection.java b/src/org/apache/commons/collections4/collection/TransformedCollection.java new file mode 100644 index 0000000..9c43eca --- /dev/null +++ b/src/org/apache/commons/collections4/collection/TransformedCollection.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another {@link Collection} to transform objects that are added. + *

          + * The add methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

          + * This class is Serializable from Commons Collections 3.1. + * + * @param the type of the elements in the collection + * @since 3.0 + * @version $Id: TransformedCollection.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedCollection extends AbstractCollectionDecorator { + + /** Serialization version */ + private static final long serialVersionUID = 8692300188161871514L; + + /** The transformer to use */ + protected final Transformer transformer; + + /** + * Factory method to create a transforming collection. + *

          + * If there are any elements already in the collection being decorated, they + * are NOT transformed. + * Contrast this with {@link #transformedCollection(Collection, Transformer)}. + * + * @param the type of the elements in the collection + * @param coll the collection to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed collection + * @throws NullPointerException if collection or transformer is null + * @since 4.0 + */ + public static TransformedCollection transformingCollection(final Collection coll, + final Transformer transformer) { + return new TransformedCollection(coll, transformer); + } + + /** + * Factory method to create a transforming collection that will transform + * existing contents of the specified collection. + *

          + * If there are any elements already in the collection being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingCollection(Collection, Transformer)}. + * + * @param the type of the elements in the collection + * @param collection the collection to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed Collection + * @throws NullPointerException if collection or transformer is null + * @since 4.0 + */ + public static TransformedCollection transformedCollection(final Collection collection, + final Transformer transformer) { + + final TransformedCollection decorated = new TransformedCollection(collection, transformer); + // null collection & transformer are disallowed by the constructor call above + if (collection.size() > 0) { + @SuppressWarnings("unchecked") // collection is of type E + final E[] values = (E[]) collection.toArray(); // NOPMD - false positive for generics + collection.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

          + * If there are any elements already in the collection being decorated, they + * are NOT transformed. + * + * @param coll the collection to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if collection or transformer is null + */ + protected TransformedCollection(final Collection coll, final Transformer transformer) { + super(coll); + if (transformer == null) { + throw new NullPointerException("Transformer must not be null"); + } + this.transformer = transformer; + } + + /** + * Transforms an object. + *

          + * The transformer itself may throw an exception if necessary. + * + * @param object the object to transform + * @return a transformed object + */ + protected E transform(final E object) { + return transformer.transform(object); + } + + /** + * Transforms a collection. + *

          + * The transformer itself may throw an exception if necessary. + * + * @param coll the collection to transform + * @return a transformed object + */ + protected Collection transform(final Collection coll) { + final List list = new ArrayList(coll.size()); + for (final E item : coll) { + list.add(transform(item)); + } + return list; + } + + //----------------------------------------------------------------------- + @Override + public boolean add(final E object) { + return decorated().add(transform(object)); + } + + @Override + public boolean addAll(final Collection coll) { + return decorated().addAll(transform(coll)); + } + +} diff --git a/src/org/apache/commons/collections4/collection/UnmodifiableBoundedCollection.java b/src/org/apache/commons/collections4/collection/UnmodifiableBoundedCollection.java new file mode 100644 index 0000000..ccbc3e3 --- /dev/null +++ b/src/org/apache/commons/collections4/collection/UnmodifiableBoundedCollection.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.commons.collections4.BoundedCollection; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; + +/** + * {@link UnmodifiableBoundedCollection} decorates another + * {@link BoundedCollection} to ensure it can't be altered. + *

          + * If a BoundedCollection is first wrapped in some other collection decorator, + * such as synchronized or predicated, the BoundedCollection methods are no + * longer accessible. + * The factory on this class will attempt to retrieve the bounded nature by + * examining the package scope variables. + *

          + * This class is Serializable from Commons Collections 3.1. + *

          + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableBoundedCollection.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableBoundedCollection extends AbstractCollectionDecorator + implements BoundedCollection, Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = -7112672385450340330L; + + /** + * Factory method to create an unmodifiable bounded collection. + * + * @param the type of the elements in the collection + * @param coll the BoundedCollection to decorate, must not be null + * @return a new unmodifiable bounded collection + * @throws NullPointerException if {@code coll} is {@code null} + * @since 4.0 + */ + public static BoundedCollection unmodifiableBoundedCollection(final BoundedCollection coll) { + if (coll instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final BoundedCollection tmpColl = (BoundedCollection) coll; + return tmpColl; + } + return new UnmodifiableBoundedCollection(coll); + } + + /** + * Factory method to create an unmodifiable bounded collection. + *

          + * This method is capable of drilling down through up to 1000 other decorators + * to find a suitable BoundedCollection. + * + * @param the type of the elements in the collection + * @param coll the BoundedCollection to decorate, must not be null + * @return a new unmodifiable bounded collection + * @throws NullPointerException if coll is null + * @throws IllegalArgumentException if coll is not a {@code BoundedCollection} + * @since 4.0 + */ + @SuppressWarnings("unchecked") + public static BoundedCollection unmodifiableBoundedCollection(Collection coll) { + if (coll == null) { + throw new NullPointerException("Collection must not be null."); + } + + // handle decorators + for (int i = 0; i < 1000; i++) { // counter to prevent infinite looping + if (coll instanceof BoundedCollection) { + break; // normal loop exit + } + if (coll instanceof AbstractCollectionDecorator) { + coll = ((AbstractCollectionDecorator) coll).decorated(); + } else if (coll instanceof SynchronizedCollection) { + coll = ((SynchronizedCollection) coll).decorated(); + } + } + + if (coll instanceof BoundedCollection == false) { + throw new IllegalArgumentException("Collection is not a bounded collection."); + } + return new UnmodifiableBoundedCollection((BoundedCollection) coll); + } + + /** + * Constructor that wraps (not copies). + * + * @param coll the collection to decorate, must not be null + * @throws NullPointerException if coll is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableBoundedCollection(final BoundedCollection coll) { + super((BoundedCollection) coll); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public boolean isFull() { + return decorated().isFull(); + } + + @Override + public int maxSize() { + return decorated().maxSize(); + } + + @Override + protected BoundedCollection decorated() { + return (BoundedCollection) super.decorated(); + } +} diff --git a/src/org/apache/commons/collections4/collection/UnmodifiableCollection.java b/src/org/apache/commons/collections4/collection/UnmodifiableCollection.java new file mode 100644 index 0000000..05e65f6 --- /dev/null +++ b/src/org/apache/commons/collections4/collection/UnmodifiableCollection.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.collection; + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; + +/** + * Decorates another {@link Collection} to ensure it can't be altered. + *

          + * This class is Serializable from Commons Collections 3.1. + *

          + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @param the type of the elements in the collection + * @since 3.0 + * @version $Id: UnmodifiableCollection.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableCollection + extends AbstractCollectionDecorator + implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = -239892006883819945L; + + /** + * Factory method to create an unmodifiable collection. + *

          + * If the collection passed in is already unmodifiable, it is returned. + * + * @param the type of the elements in the collection + * @param coll the collection to decorate, must not be null + * @return an unmodifiable collection + * @throws NullPointerException if collection is null + * @since 4.0 + */ + public static Collection unmodifiableCollection(final Collection coll) { + if (coll instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final Collection tmpColl = (Collection) coll; + return tmpColl; + } + return new UnmodifiableCollection(coll); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param coll the collection to decorate, must not be null + * @throws NullPointerException if collection is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableCollection(final Collection coll) { + super((Collection) coll); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/org/apache/commons/collections4/collection/package-info.java b/src/org/apache/commons/collections4/collection/package-info.java new file mode 100644 index 0000000..e9c5bbf --- /dev/null +++ b/src/org/apache/commons/collections4/collection/package-info.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the + * {@link java.util.Collection Collection} interface. + *

          + * The following implementations are provided in the package: + *

            + *
          • CompositeCollection - a collection that combines multiple collections into one + *
          + * The following decorators are provided in the package: + *
            + *
          • Synchronized - synchronizes method access for multi-threaded environments + *
          • Unmodifiable - ensures the collection cannot be altered + *
          • Predicated - ensures that only elements that are valid according to a predicate can be added + *
          • Transformed - transforms elements as they are added + *
          • Indexed - provides a map-like view onto another collection + *
          + * + * @version $Id: package-info.java 1477746 2013-04-30 18:11:20Z tn $ + */ +package org.apache.commons.collections4.collection; diff --git a/src/org/apache/commons/collections4/comparators/BooleanComparator.java b/src/org/apache/commons/collections4/comparators/BooleanComparator.java new file mode 100644 index 0000000..fb4fa76 --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/BooleanComparator.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.comparators; + +import java.io.Serializable; +import java.util.Comparator; + +/** + * A {@link Comparator} for {@link Boolean} objects that can sort either + * true or false first. + *

          + * @see #getTrueFirstComparator() + * @see #getFalseFirstComparator() + * @see #booleanComparator(boolean) + * + * @since 3.0 + * @version $Id: BooleanComparator.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public final class BooleanComparator implements Comparator, Serializable { + + /** Serialization version. */ + private static final long serialVersionUID = 1830042991606340609L; + + /** Constant "true first" reference. */ + private static final BooleanComparator TRUE_FIRST = new BooleanComparator(true); + + /** Constant "false first" reference. */ + private static final BooleanComparator FALSE_FIRST = new BooleanComparator(false); + + /** true iff true values sort before false values. */ + private boolean trueFirst = false; + + //----------------------------------------------------------------------- + /** + * Returns a BooleanComparator instance that sorts + * true values before false values. + *

          + * Clients are encouraged to use the value returned from + * this method instead of constructing a new instance + * to reduce allocation and garbage collection overhead when + * multiple BooleanComparators may be used in the same + * virtual machine. + * + * @return the true first singleton BooleanComparator + */ + public static BooleanComparator getTrueFirstComparator() { + return TRUE_FIRST; + } + + /** + * Returns a BooleanComparator instance that sorts + * false values before true values. + *

          + * Clients are encouraged to use the value returned from + * this method instead of constructing a new instance + * to reduce allocation and garbage collection overhead when + * multiple BooleanComparators may be used in the same + * virtual machine. + * + * @return the false first singleton BooleanComparator + */ + public static BooleanComparator getFalseFirstComparator() { + return FALSE_FIRST; + } + + /** + * Returns a BooleanComparator instance that sorts + * trueFirst values before + * !trueFirst values. + *

          + * Clients are encouraged to use the value returned from + * this method instead of constructing a new instance + * to reduce allocation and garbage collection overhead when + * multiple BooleanComparators may be used in the same + * virtual machine. + * + * @param trueFirst when true, sort + * true Booleans before false + * @return a singleton BooleanComparator instance + * @since 4.0 + */ + public static BooleanComparator booleanComparator(final boolean trueFirst) { + return trueFirst ? TRUE_FIRST : FALSE_FIRST; + } + + //----------------------------------------------------------------------- + /** + * Creates a BooleanComparator that sorts + * false values before true values. + *

          + * Equivalent to {@link #BooleanComparator(boolean) BooleanComparator(false)}. + *

          + * Please use the static factory instead whenever possible. + */ + public BooleanComparator() { + this(false); + } + + /** + * Creates a BooleanComparator that sorts + * trueFirst values before + * !trueFirst values. + *

          + * Please use the static factories instead whenever possible. + * + * @param trueFirst when true, sort + * true boolean values before false + */ + public BooleanComparator(final boolean trueFirst) { + this.trueFirst = trueFirst; + } + + //----------------------------------------------------------------------- + /** + * Compares two non-null Boolean objects + * according to the value of {@link #sortsTrueFirst()}. + * + * @param b1 the first boolean to compare + * @param b2 the second boolean to compare + * @return negative if obj1 is less, positive if greater, zero if equal + * @throws NullPointerException when either argument null + */ + @Override + public int compare(final Boolean b1, final Boolean b2) { + final boolean v1 = b1.booleanValue(); + final boolean v2 = b2.booleanValue(); + + return (v1 ^ v2) ? ( (v1 ^ trueFirst) ? 1 : -1 ) : 0; + } + + //----------------------------------------------------------------------- + /** + * Implement a hash code for this comparator that is consistent with + * {@link #equals(Object) equals}. + * + * @return a hash code for this comparator. + */ + @Override + public int hashCode() { + final int hash = "BooleanComparator".hashCode(); + return trueFirst ? -1 * hash : hash; + } + + /** + * Returns true iff that Object is + * is a {@link Comparator} whose ordering is known to be + * equivalent to mine. + *

          + * This implementation returns true + * iff that is a {@link BooleanComparator} + * whose value of {@link #sortsTrueFirst()} is equal to mine. + * + * @param object the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object object) { + return (this == object) || + ((object instanceof BooleanComparator) && + (this.trueFirst == ((BooleanComparator)object).trueFirst)); + } + + //----------------------------------------------------------------------- + /** + * Returns true iff + * I sort true values before + * false values. In other words, + * returns true iff + * {@link #compare(Boolean,Boolean) compare(Boolean.FALSE,Boolean.TRUE)} + * returns a positive value. + * + * @return the trueFirst flag + */ + public boolean sortsTrueFirst() { + return trueFirst; + } + +} diff --git a/src/org/apache/commons/collections4/comparators/ComparableComparator.java b/src/org/apache/commons/collections4/comparators/ComparableComparator.java new file mode 100644 index 0000000..23bc964 --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/ComparableComparator.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.comparators; + +import java.io.Serializable; +import java.util.Comparator; + +/** + * A {@link Comparator Comparator} that compares {@link Comparable Comparable} + * objects. + *

          + * This Comparator is useful, for example, for enforcing the natural order in + * custom implementations of {@link java.util.SortedSet SortedSet} and + * {@link java.util.SortedMap SortedMap}. + *

          + * Note: In the 2.0 and 2.1 releases of Commons Collections, this class would + * throw a {@link ClassCastException} if either of the arguments to + * {@link #compare(Object, Object) compare} were null, not + * {@link Comparable Comparable}, or for which + * {@link Comparable#compareTo(Object) compareTo} gave inconsistent results. + * This is no longer the case. See {@link #compare(Object, Object) compare} for + * details. + * + * @since 2.0 + * @version $Id: ComparableComparator.java 1683951 2015-06-06 20:19:03Z tn $ + * + * @see java.util.Collections#reverseOrder() + */ +public class ComparableComparator> implements Comparator, Serializable { + + /** Serialization version. */ + private static final long serialVersionUID=-291439688585137865L; + + /** The singleton instance. */ + @SuppressWarnings("rawtypes") + public static final ComparableComparator INSTANCE = new ComparableComparator(); + + //----------------------------------------------------------------------- + /** + * Gets the singleton instance of a ComparableComparator. + *

          + * Developers are encouraged to use the comparator returned from this method + * instead of constructing a new instance to reduce allocation and GC overhead + * when multiple comparable comparators may be used in the same VM. + * + * @param the element type + * @return the singleton ComparableComparator + * @since 4.0 + */ + @SuppressWarnings("unchecked") + public static > ComparableComparator comparableComparator() { + return INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Constructor whose use should be avoided. + *

          + * Please use the {@link #comparableComparator()} method whenever possible. + */ + public ComparableComparator() { + super(); + } + + //----------------------------------------------------------------------- + /** + * Compare the two {@link Comparable Comparable} arguments. + * This method is equivalent to: + *

          ((Comparable)obj1).compareTo(obj2)
          + * + * @param obj1 the first object to compare + * @param obj2 the second object to compare + * @return negative if obj1 is less, positive if greater, zero if equal + * @throws NullPointerException if obj1 is null, + * or when ((Comparable)obj1).compareTo(obj2) does + * @throws ClassCastException if obj1 is not a Comparable, + * or when ((Comparable)obj1).compareTo(obj2) does + */ + @Override + public int compare(final E obj1, final E obj2) { + return obj1.compareTo(obj2); + } + + //----------------------------------------------------------------------- + /** + * Implement a hash code for this comparator that is consistent with + * {@link #equals(Object) equals}. + * + * @return a hash code for this comparator. + * @since 3.0 + */ + @Override + public int hashCode() { + return "ComparableComparator".hashCode(); + } + + /** + * Returns {@code true} iff that Object is is a {@link Comparator Comparator} + * whose ordering is known to be equivalent to mine. + *

          + * This implementation returns {@code true} iff + * object.{@link Object#getClass() getClass()} equals + * this.getClass(). Subclasses may want to override this behavior to remain + * consistent with the {@link Comparator#equals(Object)} contract. + * + * @param object the object to compare with + * @return {@code true} if equal + * @since 3.0 + */ + @Override + public boolean equals(final Object object) { + return this == object || + null != object && object.getClass().equals(this.getClass()); + } + +} diff --git a/src/org/apache/commons/collections4/comparators/ComparatorChain.java b/src/org/apache/commons/collections4/comparators/ComparatorChain.java new file mode 100644 index 0000000..651527a --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/ComparatorChain.java @@ -0,0 +1,349 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.comparators; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * A ComparatorChain is a Comparator that wraps one or more Comparators in + * sequence. The ComparatorChain calls each Comparator in sequence until either + * 1) any single Comparator returns a non-zero result (and that result is then + * returned), or 2) the ComparatorChain is exhausted (and zero is returned). + * This type of sorting is very similar to multi-column sorting in SQL, and this + * class allows Java classes to emulate that kind of behaviour when sorting a + * List. + *

          + * To further facilitate SQL-like sorting, the order of any single Comparator in + * the list can be reversed. + *

          + * Calling a method that adds new Comparators or changes the ascend/descend sort + * after compare(Object, Object) has been called will result in an + * UnsupportedOperationException. However, take care to not alter the + * underlying List of Comparators or the BitSet that defines the sort order. + *

          + * Instances of ComparatorChain are not synchronized. The class is not + * thread-safe at construction time, but it is thread-safe to perform + * multiple comparisons after all the setup operations are complete. + * + * @since 2.0 + * @version $Id: ComparatorChain.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public class ComparatorChain implements Comparator, Serializable { + + /** Serialization version from Collections 2.0. */ + private static final long serialVersionUID = -721644942746081630L; + + /** The list of comparators in the chain. */ + private final List> comparatorChain; + /** Order - false (clear) = ascend; true (set) = descend. */ + private BitSet orderingBits = null; + /** Whether the chain has been "locked". */ + private boolean isLocked = false; + + //----------------------------------------------------------------------- + /** + * Construct a ComparatorChain with no Comparators. + * You must add at least one Comparator before calling + * the compare(Object,Object) method, or an + * UnsupportedOperationException is thrown + */ + public ComparatorChain() { + this(new ArrayList>(), new BitSet()); + } + + /** + * Construct a ComparatorChain with a single Comparator, + * sorting in the forward order + * + * @param comparator First comparator in the Comparator chain + */ + public ComparatorChain(final Comparator comparator) { + this(comparator, false); + } + + /** + * Construct a Comparator chain with a single Comparator, + * sorting in the given order + * + * @param comparator First Comparator in the ComparatorChain + * @param reverse false = forward sort; true = reverse sort + */ + public ComparatorChain(final Comparator comparator, final boolean reverse) { + comparatorChain = new ArrayList>(1); + comparatorChain.add(comparator); + orderingBits = new BitSet(1); + if (reverse == true) { + orderingBits.set(0); + } + } + + /** + * Construct a ComparatorChain from the Comparators in the + * List. All Comparators will default to the forward + * sort order. + * + * @param list List of Comparators + * @see #ComparatorChain(List,BitSet) + */ + public ComparatorChain(final List> list) { + this(list, new BitSet(list.size())); + } + + /** + * Construct a ComparatorChain from the Comparators in the + * given List. The sort order of each column will be + * drawn from the given BitSet. When determining the sort + * order for Comparator at index i in the List, + * the ComparatorChain will call BitSet.get(i). + * If that method returns false, the forward + * sort order is used; a return value of true + * indicates reverse sort order. + * + * @param list List of Comparators. NOTE: This constructor does not perform a + * defensive copy of the list + * @param bits Sort order for each Comparator. Extra bits are ignored, + * unless extra Comparators are added by another method. + */ + public ComparatorChain(final List> list, final BitSet bits) { + comparatorChain = list; + orderingBits = bits; + } + + //----------------------------------------------------------------------- + /** + * Add a Comparator to the end of the chain using the + * forward sort order + * + * @param comparator Comparator with the forward sort order + */ + public void addComparator(final Comparator comparator) { + addComparator(comparator, false); + } + + /** + * Add a Comparator to the end of the chain using the + * given sort order + * + * @param comparator Comparator to add to the end of the chain + * @param reverse false = forward sort order; true = reverse sort order + */ + public void addComparator(final Comparator comparator, final boolean reverse) { + checkLocked(); + + comparatorChain.add(comparator); + if (reverse == true) { + orderingBits.set(comparatorChain.size() - 1); + } + } + + /** + * Replace the Comparator at the given index, maintaining + * the existing sort order. + * + * @param index index of the Comparator to replace + * @param comparator Comparator to place at the given index + * @exception IndexOutOfBoundsException + * if index < 0 or index >= size() + */ + public void setComparator(final int index, final Comparator comparator) throws IndexOutOfBoundsException { + setComparator(index, comparator, false); + } + + /** + * Replace the Comparator at the given index in the + * ComparatorChain, using the given sort order + * + * @param index index of the Comparator to replace + * @param comparator Comparator to set + * @param reverse false = forward sort order; true = reverse sort order + */ + public void setComparator(final int index, final Comparator comparator, final boolean reverse) { + checkLocked(); + + comparatorChain.set(index,comparator); + if (reverse == true) { + orderingBits.set(index); + } else { + orderingBits.clear(index); + } + } + + /** + * Change the sort order at the given index in the + * ComparatorChain to a forward sort. + * + * @param index Index of the ComparatorChain + */ + public void setForwardSort(final int index) { + checkLocked(); + orderingBits.clear(index); + } + + /** + * Change the sort order at the given index in the + * ComparatorChain to a reverse sort. + * + * @param index Index of the ComparatorChain + */ + public void setReverseSort(final int index) { + checkLocked(); + orderingBits.set(index); + } + + /** + * Number of Comparators in the current ComparatorChain. + * + * @return Comparator count + */ + public int size() { + return comparatorChain.size(); + } + + /** + * Determine if modifications can still be made to the + * ComparatorChain. ComparatorChains cannot be modified + * once they have performed a comparison. + * + * @return true = ComparatorChain cannot be modified; false = + * ComparatorChain can still be modified. + */ + public boolean isLocked() { + return isLocked; + } + + /** + * Throws an exception if the {@link ComparatorChain} is locked. + * + * @throws UnsupportedOperationException if the {@link ComparatorChain} is locked + */ + private void checkLocked() { + if (isLocked == true) { + throw new UnsupportedOperationException( + "Comparator ordering cannot be changed after the first comparison is performed"); + } + } + + /** + * Throws an exception if the {@link ComparatorChain} is empty. + * + * @throws UnsupportedOperationException if the {@link ComparatorChain} is empty + */ + private void checkChainIntegrity() { + if (comparatorChain.size() == 0) { + throw new UnsupportedOperationException("ComparatorChains must contain at least one Comparator"); + } + } + + //----------------------------------------------------------------------- + /** + * Perform comparisons on the Objects as per + * Comparator.compare(o1,o2). + * + * @param o1 the first object to compare + * @param o2 the second object to compare + * @return -1, 0, or 1 + * @throws UnsupportedOperationException if the ComparatorChain does not contain at least one Comparator + */ + @Override + public int compare(final E o1, final E o2) throws UnsupportedOperationException { + if (isLocked == false) { + checkChainIntegrity(); + isLocked = true; + } + + // iterate over all comparators in the chain + final Iterator> comparators = comparatorChain.iterator(); + for (int comparatorIndex = 0; comparators.hasNext(); ++comparatorIndex) { + + final Comparator comparator = comparators.next(); + int retval = comparator.compare(o1,o2); + if (retval != 0) { + // invert the order if it is a reverse sort + if (orderingBits.get(comparatorIndex) == true) { + if (retval > 0) { + retval = -1; + } else { + retval = 1; + } + } + return retval; + } + } + + // if comparators are exhausted, return 0 + return 0; + } + + //----------------------------------------------------------------------- + /** + * Implement a hash code for this comparator that is consistent with + * {@link #equals(Object) equals}. + * + * @return a suitable hash code + * @since 3.0 + */ + @Override + public int hashCode() { + int hash = 0; + if (null != comparatorChain) { + hash ^= comparatorChain.hashCode(); + } + if (null != orderingBits) { + hash ^= orderingBits.hashCode(); + } + return hash; + } + + /** + * Returns true iff that Object is + * is a {@link Comparator} whose ordering is known to be + * equivalent to mine. + *

          + * This implementation returns true + * iff object.{@link Object#getClass() getClass()} + * equals this.getClass(), and the underlying + * comparators and order bits are equal. + * Subclasses may want to override this behavior to remain consistent + * with the {@link Comparator#equals(Object)} contract. + * + * @param object the object to compare with + * @return true if equal + * @since 3.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (null == object) { + return false; + } + if (object.getClass().equals(this.getClass())) { + final ComparatorChain chain = (ComparatorChain) object; + return (null == orderingBits ? null == chain.orderingBits : orderingBits.equals(chain.orderingBits)) && + (null == comparatorChain ? null == chain.comparatorChain : + comparatorChain.equals(chain.comparatorChain)); + } + return false; + } + +} diff --git a/src/org/apache/commons/collections4/comparators/FixedOrderComparator.java b/src/org/apache/commons/collections4/comparators/FixedOrderComparator.java new file mode 100644 index 0000000..31cb2a3 --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/FixedOrderComparator.java @@ -0,0 +1,300 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.comparators; + +import java.io.Serializable; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A Comparator which imposes a specific order on a specific set of Objects. + * Objects are presented to the FixedOrderComparator in a specified order and + * subsequent calls to {@link #compare(Object, Object) compare} yield that order. + * For example: + *

          + * String[] planets = {"Mercury", "Venus", "Earth", "Mars"};
          + * FixedOrderComparator distanceFromSun = new FixedOrderComparator(planets);
          + * Arrays.sort(planets);                     // Sort to alphabetical order
          + * Arrays.sort(planets, distanceFromSun);    // Back to original order
          + * 
          + *

          + * Once compare has been called, the FixedOrderComparator is locked + * and attempts to modify it yield an UnsupportedOperationException. + *

          + * Instances of FixedOrderComparator are not synchronized. The class is not + * thread-safe at construction time, but it is thread-safe to perform + * multiple comparisons after all the setup operations are complete. + *

          + * This class is Serializable from Commons Collections 4.0. + * + * @since 3.0 + * @version $Id: FixedOrderComparator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class FixedOrderComparator implements Comparator, Serializable { + + /** Serialization version from Collections 4.0. */ + private static final long serialVersionUID = 82794675842863201L; + + /** + * Unknown object behavior enum. + * @since 4.0 + */ + public static enum UnknownObjectBehavior { + BEFORE, AFTER, EXCEPTION; + } + + /** Internal map of object to position */ + private final Map map = new HashMap(); + + /** Counter used in determining the position in the map */ + private int counter = 0; + + /** Is the comparator locked against further change */ + private boolean isLocked = false; + + /** The behaviour in the case of an unknown object */ + private UnknownObjectBehavior unknownObjectBehavior = UnknownObjectBehavior.EXCEPTION; + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructs an empty FixedOrderComparator. + */ + public FixedOrderComparator() { + super(); + } + + /** + * Constructs a FixedOrderComparator which uses the order of the given array + * to compare the objects. + *

          + * The array is copied, so later changes will not affect the comparator. + * + * @param items the items that the comparator can compare in order + * @throws NullPointerException if the array is null + */ + @SafeVarargs + public FixedOrderComparator(final T... items) { + super(); + if (items == null) { + throw new NullPointerException("The list of items must not be null"); + } + for (final T item : items) { + add(item); + } + } + + /** + * Constructs a FixedOrderComparator which uses the order of the given list + * to compare the objects. + *

          + * The list is copied, so later changes will not affect the comparator. + * + * @param items the items that the comparator can compare in order + * @throws NullPointerException if the list is null + */ + public FixedOrderComparator(final List items) { + super(); + if (items == null) { + throw new NullPointerException("The list of items must not be null"); + } + for (final T t : items) { + add(t); + } + } + + // Bean methods / state querying methods + //----------------------------------------------------------------------- + /** + * Returns true if modifications cannot be made to the FixedOrderComparator. + * FixedOrderComparators cannot be modified once they have performed a comparison. + * + * @return true if attempts to change the FixedOrderComparator yield an + * UnsupportedOperationException, false if it can be changed. + */ + public boolean isLocked() { + return isLocked; + } + + /** + * Checks to see whether the comparator is now locked against further changes. + * + * @throws UnsupportedOperationException if the comparator is locked + */ + protected void checkLocked() { + if (isLocked()) { + throw new UnsupportedOperationException("Cannot modify a FixedOrderComparator after a comparison"); + } + } + + /** + * Gets the behavior for comparing unknown objects. + * + * @return {@link UnknownObjectBehavior} + */ + public UnknownObjectBehavior getUnknownObjectBehavior() { + return unknownObjectBehavior; + } + + /** + * Sets the behavior for comparing unknown objects. + * + * @param unknownObjectBehavior the flag for unknown behaviour - + * UNKNOWN_AFTER, UNKNOWN_BEFORE or UNKNOWN_THROW_EXCEPTION + * @throws UnsupportedOperationException if a comparison has been performed + * @throws NullPointerException if unknownObjectBehavior is null + */ + public void setUnknownObjectBehavior(final UnknownObjectBehavior unknownObjectBehavior) { + checkLocked(); + if (unknownObjectBehavior == null) { + throw new NullPointerException("Unknown object behavior must not be null"); + } + this.unknownObjectBehavior = unknownObjectBehavior; + } + + // Methods for adding items + //----------------------------------------------------------------------- + /** + * Adds an item, which compares as after all items known to the Comparator. + * If the item is already known to the Comparator, its old position is + * replaced with the new position. + * + * @param obj the item to be added to the Comparator. + * @return true if obj has been added for the first time, false if + * it was already known to the Comparator. + * @throws UnsupportedOperationException if a comparison has already been made + */ + public boolean add(final T obj) { + checkLocked(); + final Integer position = map.put(obj, Integer.valueOf(counter++)); + return position == null; + } + + /** + * Adds a new item, which compares as equal to the given existing item. + * + * @param existingObj an item already in the Comparator's set of + * known objects + * @param newObj an item to be added to the Comparator's set of + * known objects + * @return true if newObj has been added for the first time, false if + * it was already known to the Comparator. + * @throws IllegalArgumentException if existingObject is not in the + * Comparator's set of known objects. + * @throws UnsupportedOperationException if a comparison has already been made + */ + public boolean addAsEqual(final T existingObj, final T newObj) { + checkLocked(); + final Integer position = map.get(existingObj); + if (position == null) { + throw new IllegalArgumentException(existingObj + " not known to " + this); + } + final Integer result = map.put(newObj, position); + return result == null; + } + + // Comparator methods + //----------------------------------------------------------------------- + /** + * Compares two objects according to the order of this Comparator. + *

          + * It is important to note that this class will throw an IllegalArgumentException + * in the case of an unrecognised object. This is not specified in the + * Comparator interface, but is the most appropriate exception. + * + * @param obj1 the first object to compare + * @param obj2 the second object to compare + * @return negative if obj1 is less, positive if greater, zero if equal + * @throws IllegalArgumentException if obj1 or obj2 are not known + * to this Comparator and an alternative behavior has not been set + * via {@link #setUnknownObjectBehavior(UnknownObjectBehavior)}. + */ + @Override + public int compare(final T obj1, final T obj2) { + isLocked = true; + final Integer position1 = map.get(obj1); + final Integer position2 = map.get(obj2); + if (position1 == null || position2 == null) { + switch (unknownObjectBehavior) { + case BEFORE: + return position1 == null ? position2 == null ? 0 : -1 : 1; + case AFTER: + return position1 == null ? position2 == null ? 0 : 1 : -1; + case EXCEPTION: + final Object unknownObj = position1 == null ? obj1 : obj2; + throw new IllegalArgumentException("Attempting to compare unknown object " + + unknownObj); + default: //could be null + throw new UnsupportedOperationException("Unknown unknownObjectBehavior: " + + unknownObjectBehavior); + } + } + return position1.compareTo(position2); + } + + //----------------------------------------------------------------------- + /** + * Implement a hash code for this comparator that is consistent with + * {@link #equals(Object) equals}. + * + * @return a hash code for this comparator. + */ + @Override + public int hashCode() { + int total = 17; + total = total*37 + (map == null ? 0 : map.hashCode()); + total = total*37 + (unknownObjectBehavior == null ? 0 : unknownObjectBehavior.hashCode()); + total = total*37 + counter; + total = total*37 + (isLocked ? 0 : 1); + return total; + } + + /** + * Returns true iff that Object is + * is a {@link Comparator} whose ordering is known to be + * equivalent to mine. + *

          + * This implementation returns true + * iff that is a {@link FixedOrderComparator} + * whose attributes are equal to mine. + * + * @param object the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (null == object) { + return false; + } + if (object.getClass().equals(this.getClass())) { + final FixedOrderComparator comp = (FixedOrderComparator) object; + return (null == map ? null == comp.map : map.equals(comp.map)) && + (null == unknownObjectBehavior ? null == comp.unknownObjectBehavior : + unknownObjectBehavior == comp.unknownObjectBehavior && + counter == comp.counter && + isLocked == comp.isLocked && + unknownObjectBehavior == comp.unknownObjectBehavior); + } + return false; + } + +} diff --git a/src/org/apache/commons/collections4/comparators/NullComparator.java b/src/org/apache/commons/collections4/comparators/NullComparator.java new file mode 100644 index 0000000..15093ec --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/NullComparator.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.comparators; + +import java.io.Serializable; +import java.util.Comparator; + +import org.apache.commons.collections4.ComparatorUtils; + +/** + * A Comparator that will compare nulls to be either lower or higher than + * other objects. + * + * @since 2.0 + * @version $Id: NullComparator.java 1683951 2015-06-06 20:19:03Z tn $ + */ +public class NullComparator implements Comparator, Serializable { + + /** Serialization version. */ + private static final long serialVersionUID = -5820772575483504339L; + + /** + * The comparator to use when comparing two non-null objects. + **/ + private final Comparator nonNullComparator; + + /** + * Specifies whether a null are compared as higher than + * non-null objects. + **/ + private final boolean nullsAreHigh; + + //----------------------------------------------------------------------- + /** + * Construct an instance that sorts null higher than any + * non-null object it is compared with. When comparing two + * non-null objects, the {@link ComparableComparator} is + * used. + **/ + @SuppressWarnings("unchecked") + public NullComparator() { + this(ComparatorUtils.NATURAL_COMPARATOR, true); + } + + /** + * Construct an instance that sorts null higher than any + * non-null object it is compared with. When comparing two + * non-null objects, the specified {@link Comparator} is + * used. + * + * @param nonNullComparator the comparator to use when comparing two + * non-null objects. This argument cannot be + * null + * + * @exception NullPointerException if nonNullComparator is + * null + **/ + public NullComparator(final Comparator nonNullComparator) { + this(nonNullComparator, true); + } + + /** + * Construct an instance that sorts null higher or lower than + * any non-null object it is compared with. When comparing + * two non-null objects, the {@link ComparableComparator} is + * used. + * + * @param nullsAreHigh a true value indicates that + * null should be compared as higher than a + * non-null object. A false value indicates + * that null should be compared as lower than a + * non-null object. + **/ + @SuppressWarnings("unchecked") + public NullComparator(final boolean nullsAreHigh) { + this(ComparatorUtils.NATURAL_COMPARATOR, nullsAreHigh); + } + + /** + * Construct an instance that sorts null higher or lower than + * any non-null object it is compared with. When comparing + * two non-null objects, the specified {@link Comparator} is + * used. + * + * @param nonNullComparator the comparator to use when comparing two + * non-null objects. This argument cannot be + * null + * + * @param nullsAreHigh a true value indicates that + * null should be compared as higher than a + * non-null object. A false value indicates + * that null should be compared as lower than a + * non-null object. + * + * @exception NullPointerException if nonNullComparator is + * null + **/ + public NullComparator(final Comparator nonNullComparator, final boolean nullsAreHigh) { + this.nonNullComparator = nonNullComparator; + this.nullsAreHigh = nullsAreHigh; + + if (nonNullComparator == null) { + throw new NullPointerException("null nonNullComparator"); + } + } + + //----------------------------------------------------------------------- + /** + * Perform a comparison between two objects. If both objects are + * null, a 0 value is returned. If one object + * is null and the other is not, the result is determined on + * whether the Comparator was constructed to have nulls as higher or lower + * than other objects. If neither object is null, an + * underlying comparator specified in the constructor (or the default) is + * used to compare the non-null objects. + * + * @param o1 the first object to compare + * @param o2 the object to compare it to. + * @return -1 if o1 is "lower" than (less than, + * before, etc.) o2; 1 if o1 is + * "higher" than (greater than, after, etc.) o2; or + * 0 if o1 and o2 are equal. + **/ + @Override + public int compare(final E o1, final E o2) { + if(o1 == o2) { return 0; } + if(o1 == null) { return this.nullsAreHigh ? 1 : -1; } + if(o2 == null) { return this.nullsAreHigh ? -1 : 1; } + return this.nonNullComparator.compare(o1, o2); + } + + //----------------------------------------------------------------------- + /** + * Implement a hash code for this comparator that is consistent with + * {@link #equals(Object)}. + * + * @return a hash code for this comparator. + **/ + @Override + public int hashCode() { + return (nullsAreHigh ? -1 : 1) * nonNullComparator.hashCode(); + } + + /** + * Determines whether the specified object represents a comparator that is + * equal to this comparator. + * + * @param obj the object to compare this comparator with. + * + * @return true if the specified object is a NullComparator + * with equivalent null comparison behavior + * (i.e. null high or low) and with equivalent underlying + * non-null object comparators. + **/ + @Override + public boolean equals(final Object obj) { + if(obj == null) { return false; } + if(obj == this) { return true; } + if(!obj.getClass().equals(this.getClass())) { return false; } + + final NullComparator other = (NullComparator) obj; + + return this.nullsAreHigh == other.nullsAreHigh && + this.nonNullComparator.equals(other.nonNullComparator); + } + +} diff --git a/src/org/apache/commons/collections4/comparators/ReverseComparator.java b/src/org/apache/commons/collections4/comparators/ReverseComparator.java new file mode 100644 index 0000000..4ea056b --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/ReverseComparator.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.comparators; + +import java.io.Serializable; +import java.util.Comparator; + +import org.apache.commons.collections4.ComparatorUtils; + +/** + * Reverses the order of another comparator by reversing the arguments + * to its {@link #compare(Object, Object) compare} method. + * + * @since 2.0 + * @version $Id: ReverseComparator.java 1683951 2015-06-06 20:19:03Z tn $ + * + * @see java.util.Collections#reverseOrder() + */ +public class ReverseComparator implements Comparator, Serializable { + + /** Serialization version from Collections 2.0. */ + private static final long serialVersionUID = 2858887242028539265L; + + /** The comparator being decorated. */ + private final Comparator comparator; + + //----------------------------------------------------------------------- + /** + * Creates a comparator that compares objects based on the inverse of their + * natural ordering. Using this Constructor will create a ReverseComparator + * that is functionally identical to the Comparator returned by + * java.util.Collections.reverseOrder(). + * + * @see java.util.Collections#reverseOrder() + */ + public ReverseComparator() { + this(null); + } + + /** + * Creates a comparator that inverts the comparison + * of the given comparator. If you pass in null, + * the ReverseComparator defaults to reversing the + * natural order, as per {@link java.util.Collections#reverseOrder()}. + * + * @param comparator Comparator to reverse + */ + @SuppressWarnings("unchecked") + public ReverseComparator(final Comparator comparator) { + this.comparator = comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : comparator; + } + + //----------------------------------------------------------------------- + /** + * Compares two objects in reverse order. + * + * @param obj1 the first object to compare + * @param obj2 the second object to compare + * @return negative if obj1 is less, positive if greater, zero if equal + */ + @Override + public int compare(final E obj1, final E obj2) { + return comparator.compare(obj2, obj1); + } + + //----------------------------------------------------------------------- + /** + * Implement a hash code for this comparator that is consistent with + * {@link #equals(Object) equals}. + * + * @return a suitable hash code + * @since 3.0 + */ + @Override + public int hashCode() { + return "ReverseComparator".hashCode() ^ comparator.hashCode(); + } + + /** + * Returns true iff that Object is + * is a {@link Comparator} whose ordering is known to be + * equivalent to mine. + *

          + * This implementation returns true + * iff object.{@link Object#getClass() getClass()} + * equals this.getClass(), and the underlying + * comparators are equal. + * Subclasses may want to override this behavior to remain consistent + * with the {@link Comparator#equals(Object) equals} contract. + * + * @param object the object to compare to + * @return true if equal + * @since 3.0 + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (null == object) { + return false; + } + if (object.getClass().equals(this.getClass())) { + final ReverseComparator thatrc = (ReverseComparator) object; + return comparator.equals(thatrc.comparator); + } + return false; + } + +} diff --git a/src/org/apache/commons/collections4/comparators/TransformingComparator.java b/src/org/apache/commons/collections4/comparators/TransformingComparator.java new file mode 100644 index 0000000..fc34435 --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/TransformingComparator.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.comparators; + +import java.io.Serializable; +import java.util.Comparator; + +import org.apache.commons.collections4.ComparatorUtils; +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another Comparator with transformation behavior. That is, the + * return value from the transform operation will be passed to the decorated + * {@link Comparator#compare(Object,Object) compare} method. + *

          + * This class is Serializable from Commons Collections 4.0. + * + * @since 2.1 + * @version $Id: TransformingComparator.java 1683951 2015-06-06 20:19:03Z tn $ + * + * @see org.apache.commons.collections4.Transformer + * @see org.apache.commons.collections4.comparators.ComparableComparator + */ +public class TransformingComparator implements Comparator, Serializable { + + /** Serialization version from Collections 4.0. */ + private static final long serialVersionUID = 3456940356043606220L; + + /** The decorated comparator. */ + private final Comparator decorated; + /** The transformer being used. */ + private final Transformer transformer; + + //----------------------------------------------------------------------- + /** + * Constructs an instance with the given Transformer and a + * {@link ComparableComparator ComparableComparator}. + * + * @param transformer what will transform the arguments to compare + */ + @SuppressWarnings("unchecked") + public TransformingComparator(final Transformer transformer) { + this(transformer, ComparatorUtils.NATURAL_COMPARATOR); + } + + /** + * Constructs an instance with the given Transformer and Comparator. + * + * @param transformer what will transform the arguments to compare + * @param decorated the decorated Comparator + */ + public TransformingComparator(final Transformer transformer, + final Comparator decorated) { + this.decorated = decorated; + this.transformer = transformer; + } + + //----------------------------------------------------------------------- + /** + * Returns the result of comparing the values from the transform operation. + * + * @param obj1 the first object to transform then compare + * @param obj2 the second object to transform then compare + * @return negative if obj1 is less, positive if greater, zero if equal + */ + @Override + public int compare(final I obj1, final I obj2) { + final O value1 = this.transformer.transform(obj1); + final O value2 = this.transformer.transform(obj2); + return this.decorated.compare(value1, value2); + } + + //----------------------------------------------------------------------- + /** + * Implement a hash code for this comparator that is consistent with + * {@link #equals(Object) equals}. + * + * @return a hash code for this comparator. + */ + @Override + public int hashCode() { + int total = 17; + total = total*37 + (decorated == null ? 0 : decorated.hashCode()); + total = total*37 + (transformer == null ? 0 : transformer.hashCode()); + return total; + } + + /** + * Returns true iff that Object is + * is a {@link Comparator} whose ordering is known to be + * equivalent to mine. + *

          + * This implementation returns true + * iff that is a {@link TransformingComparator} + * whose attributes are equal to mine. + * + * @param object the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (null == object) { + return false; + } + if (object.getClass().equals(this.getClass())) { + final TransformingComparator comp = (TransformingComparator) object; + return (null == decorated ? null == comp.decorated : decorated.equals(comp.decorated)) && + (null == transformer ? null == comp.transformer : transformer.equals(comp.transformer)); + } + return false; + } + +} + diff --git a/src/org/apache/commons/collections4/comparators/package-info.java b/src/org/apache/commons/collections4/comparators/package-info.java new file mode 100644 index 0000000..c1e554a --- /dev/null +++ b/src/org/apache/commons/collections4/comparators/package-info.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the + * {@link java.util.Comparator Comparator} interface. + *

          + * You may also consider using + * {@link org.apache.commons.collections4.ComparatorUtils ComparatorUtils}, + * which is a single class that uses static methods to construct instances + * of the classes in this package. + * + * @version $Id: package-info.java 1477747 2013-04-30 18:16:48Z tn $ + */ +package org.apache.commons.collections4.comparators; diff --git a/src/org/apache/commons/collections4/functors/AbstractQuantifierPredicate.java b/src/org/apache/commons/collections4/functors/AbstractQuantifierPredicate.java new file mode 100644 index 0000000..0fe7605 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/AbstractQuantifierPredicate.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Abstract base class for quantification predicates, e.g. All, Any, None. + * + * @since 4.0 + * @version $Id: AbstractQuantifierPredicate.java 1543167 2013-11-18 21:21:32Z ggregory $ + */ +public abstract class AbstractQuantifierPredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -3094696765038308799L; + + /** The array of predicates to call */ + protected final Predicate[] iPredicates; + + /** + * Constructor that performs no validation. + * + * @param predicates the predicates to check, not cloned, not null + */ + @SafeVarargs + public AbstractQuantifierPredicate(final Predicate... predicates) { + iPredicates = predicates; + } + + /** + * Gets the predicates. + * + * @return a copy of the predicates + * @since 3.1 + */ + public Predicate[] getPredicates() { + return FunctorUtils.copy(iPredicates); + } + +} diff --git a/src/org/apache/commons/collections4/functors/AllPredicate.java b/src/org/apache/commons/collections4/functors/AllPredicate.java new file mode 100644 index 0000000..da1cc11 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/AllPredicate.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import static org.apache.commons.collections4.functors.FunctorUtils.coerce; +import static org.apache.commons.collections4.functors.FunctorUtils.validate; +import static org.apache.commons.collections4.functors.TruePredicate.truePredicate; + +import java.util.Collection; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if all the + * predicates return true. + * If the array of predicates is empty, then this predicate returns true. + *

          + * NOTE: In versions prior to 3.2 an array size of zero or one + * threw an exception. + * + * @since 3.0 + * @version $Id: AllPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class AllPredicate extends AbstractQuantifierPredicate { + + /** Serial version UID */ + private static final long serialVersionUID = -3094696765038308799L; + + /** + * Factory to create the predicate. + *

          + * If the array is size zero, the predicate always returns true. + * If the array is size one, then that predicate is returned. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the all predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + @SafeVarargs + public static Predicate allPredicate(final Predicate... predicates) { + FunctorUtils.validate(predicates); + if (predicates.length == 0) { + return truePredicate(); + } + if (predicates.length == 1) { + return coerce(predicates[0]); + } + + return new AllPredicate(FunctorUtils.copy(predicates)); + } + + /** + * Factory to create the predicate. + *

          + * If the collection is size zero, the predicate always returns true. + * If the collection is size one, then that predicate is returned. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the all predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + public static Predicate allPredicate(final Collection> predicates) { + final Predicate[] preds = validate(predicates); + if (preds.length == 0) { + return truePredicate(); + } + if (preds.length == 1) { + return coerce(preds[0]); + } + return new AllPredicate(preds); + } + + /** + * Constructor that performs no validation. + * Use allPredicate if you want that. + * + * @param predicates the predicates to check, not cloned, not null + */ + @SafeVarargs + public AllPredicate(final Predicate... predicates) { + super(predicates); + } + + /** + * Evaluates the predicate returning true if all predicates return true. + * + * @param object the input object + * @return true if all decorated predicates return true + */ + public boolean evaluate(final T object) { + for (final Predicate iPredicate : iPredicates) { + if (!iPredicate.evaluate(object)) { + return false; + } + } + return true; + } + +} diff --git a/src/org/apache/commons/collections4/functors/AndPredicate.java b/src/org/apache/commons/collections4/functors/AndPredicate.java new file mode 100644 index 0000000..1ef0ec9 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/AndPredicate.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if both the predicates return true. + * + * @since 3.0 + * @version $Id: AndPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class AndPredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 4189014213763186912L; + + /** The array of predicates to call */ + private final Predicate iPredicate1; + /** The array of predicates to call */ + private final Predicate iPredicate2; + + /** + * Factory to create the predicate. + * + * @param the type that the predicate queries + * @param predicate1 the first predicate to check, not null + * @param predicate2 the second predicate to check, not null + * @return the and predicate + * @throws NullPointerException if either predicate is null + */ + public static Predicate andPredicate(final Predicate predicate1, + final Predicate predicate2) { + if (predicate1 == null || predicate2 == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new AndPredicate(predicate1, predicate2); + } + + /** + * Constructor that performs no validation. + * Use andPredicate if you want that. + * + * @param predicate1 the first predicate to check, not null + * @param predicate2 the second predicate to check, not null + */ + public AndPredicate(final Predicate predicate1, final Predicate predicate2) { + super(); + iPredicate1 = predicate1; + iPredicate2 = predicate2; + } + + /** + * Evaluates the predicate returning true if both predicates return true. + * + * @param object the input object + * @return true if both decorated predicates return true + */ + public boolean evaluate(final T object) { + return iPredicate1.evaluate(object) && iPredicate2.evaluate(object); + } + + /** + * Gets the two predicates being decorated as an array. + * + * @return the predicates + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public Predicate[] getPredicates() { + return new Predicate[] {iPredicate1, iPredicate2}; + } + +} diff --git a/src/org/apache/commons/collections4/functors/AnyPredicate.java b/src/org/apache/commons/collections4/functors/AnyPredicate.java new file mode 100644 index 0000000..1e9d863 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/AnyPredicate.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.util.Collection; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if any of the + * predicates return true. + * If the array of predicates is empty, then this predicate returns false. + *

          + * NOTE: In versions prior to 3.2 an array size of zero or one + * threw an exception. + * + * @since 3.0 + * @version $Id: AnyPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class AnyPredicate extends AbstractQuantifierPredicate { + + /** Serial version UID */ + private static final long serialVersionUID = 7429999530934647542L; + + /** + * Factory to create the predicate. + *

          + * If the array is size zero, the predicate always returns false. + * If the array is size one, then that predicate is returned. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the any predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + @SuppressWarnings("unchecked") + public static Predicate anyPredicate(final Predicate... predicates) { + FunctorUtils.validate(predicates); + if (predicates.length == 0) { + return FalsePredicate.falsePredicate(); + } + if (predicates.length == 1) { + return (Predicate) predicates[0]; + } + return new AnyPredicate(FunctorUtils.copy(predicates)); + } + + /** + * Factory to create the predicate. + *

          + * If the collection is size zero, the predicate always returns false. + * If the collection is size one, then that predicate is returned. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the all predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + @SuppressWarnings("unchecked") + public static Predicate anyPredicate(final Collection> predicates) { + final Predicate[] preds = FunctorUtils.validate(predicates); + if (preds.length == 0) { + return FalsePredicate.falsePredicate(); + } + if (preds.length == 1) { + return (Predicate) preds[0]; + } + return new AnyPredicate(preds); + } + + /** + * Constructor that performs no validation. + * Use anyPredicate if you want that. + * + * @param predicates the predicates to check, not cloned, not null + */ + @SafeVarargs + public AnyPredicate(final Predicate... predicates) { + super(predicates); + } + + /** + * Evaluates the predicate returning true if any predicate returns true. + * + * @param object the input object + * @return true if any decorated predicate return true + */ + public boolean evaluate(final T object) { + for (final Predicate iPredicate : iPredicates) { + if (iPredicate.evaluate(object)) { + return true; + } + } + return false; + } + +} diff --git a/src/org/apache/commons/collections4/functors/CatchAndRethrowClosure.java b/src/org/apache/commons/collections4/functors/CatchAndRethrowClosure.java new file mode 100644 index 0000000..5fb3240 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/CatchAndRethrowClosure.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.FunctorException; + +/** + * {@link Closure} that catches any checked exception and re-throws it as a + * {@link FunctorException} runtime exception. Example usage: + * + *

          + * // Create a catch and re-throw closure via anonymous subclass
          + * CatchAndRethrowClosure<String> writer = new ThrowingClosure() {
          + *     private java.io.Writer out = // some writer
          + *
          + *     protected void executeAndThrow(String input) throws IOException {
          + *         out.write(input); // throwing of IOException allowed
          + *     }
          + * };
          + *
          + * // use catch and re-throw closure
          + * java.util.List strList = // some list
          + * try {
          + *     CollctionUtils.forAllDo(strList, writer);
          + * } catch (FunctorException ex) {
          + *     Throwable originalError = ex.getCause();
          + *     // handle error
          + * }
          + * 
          + * + * @since 4.0 + * @version $Id: CatchAndRethrowClosure.java 1477798 2013-04-30 19:49:02Z tn $ + */ +public abstract class CatchAndRethrowClosure implements Closure { + + /** + * Execute this closure on the specified input object. + * + * @param input the input to execute on + * @throws FunctorException (runtime) if the closure execution resulted in a + * checked exception. + */ + public void execute(final E input) { + try { + executeAndThrow(input); + } catch (final RuntimeException ex) { + throw ex; + } catch (final Throwable t) { + throw new FunctorException(t); + } + } + + /** + * Execute this closure on the specified input object. + * + * @param input the input to execute on + * @throws Throwable if the closure execution resulted in a checked + * exception. + */ + protected abstract void executeAndThrow(E input) throws Throwable; +} diff --git a/src/org/apache/commons/collections4/functors/ChainedClosure.java b/src/org/apache/commons/collections4/functors/ChainedClosure.java new file mode 100644 index 0000000..ad97e4f --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ChainedClosure.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; +import java.util.Collection; + +import org.apache.commons.collections4.Closure; + +/** + * Closure implementation that chains the specified closures together. + * + * @since 3.0 + * @version $Id: ChainedClosure.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ChainedClosure implements Closure, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -3520677225766901240L; + + /** The closures to call in turn */ + private final Closure[] iClosures; + + /** + * Factory method that performs validation and copies the parameter array. + * + * @param the type that the closure acts on + * @param closures the closures to chain, copied, no nulls + * @return the chained closure + * @throws NullPointerException if the closures array is null + * @throws NullPointerException if any closure in the array is null + */ + @SafeVarargs + public static Closure chainedClosure(final Closure... closures) { + FunctorUtils.validate(closures); + if (closures.length == 0) { + return NOPClosure.nopClosure(); + } + return new ChainedClosure(closures); + } + + /** + * Create a new Closure that calls each closure in turn, passing the + * result into the next closure. The ordering is that of the iterator() + * method on the collection. + * + * @param the type that the closure acts on + * @param closures a collection of closures to chain + * @return the chained closure + * @throws NullPointerException if the closures collection is null + * @throws NullPointerException if any closure in the collection is null + */ + @SuppressWarnings("unchecked") + public static Closure chainedClosure(final Collection> closures) { + if (closures == null) { + throw new NullPointerException("Closure collection must not be null"); + } + if (closures.size() == 0) { + return NOPClosure.nopClosure(); + } + // convert to array like this to guarantee iterator() ordering + final Closure[] cmds = new Closure[closures.size()]; + int i = 0; + for (final Closure closure : closures) { + cmds[i++] = closure; + } + FunctorUtils.validate(cmds); + return new ChainedClosure(false, cmds); + } + + /** + * Hidden constructor for the use by the static factory methods. + * + * @param clone if {@code true} the input argument will be cloned + * @param closures the closures to chain, no nulls + */ + @SafeVarargs + private ChainedClosure(final boolean clone, final Closure... closures) { + super(); + iClosures = clone ? FunctorUtils.copy(closures) : closures; + } + + /** + * Constructor that performs no validation. + * Use chainedClosure if you want that. + * + * @param closures the closures to chain, copied, no nulls + */ + @SafeVarargs + public ChainedClosure(final Closure... closures) { + this(true, closures); + } + + /** + * Execute a list of closures. + * + * @param input the input object passed to each closure + */ + public void execute(final E input) { + for (final Closure iClosure : iClosures) { + iClosure.execute(input); + } + } + + /** + * Gets the closures. + * + * @return a copy of the closures + * @since 3.1 + */ + public Closure[] getClosures() { + return FunctorUtils.copy(iClosures); + } + +} diff --git a/src/org/apache/commons/collections4/functors/ChainedTransformer.java b/src/org/apache/commons/collections4/functors/ChainedTransformer.java new file mode 100644 index 0000000..9fe22b2 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ChainedTransformer.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; +import java.util.Collection; + +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that chains the specified transformers together. + *

          + * The input object is passed to the first transformer. The transformed result + * is passed to the second transformer and so on. + * + * @since 3.0 + * @version $Id: ChainedTransformer.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ChainedTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 3514945074733160196L; + + /** The transformers to call in turn */ + private final Transformer[] iTransformers; + + /** + * Factory method that performs validation and copies the parameter array. + * + * @param the object type + * @param transformers the transformers to chain, copied, no nulls + * @return the chained transformer + * @throws NullPointerException if the transformers array is null + * @throws NullPointerException if any transformer in the array is null + */ + @SafeVarargs + public static Transformer chainedTransformer(final Transformer... transformers) { + FunctorUtils.validate(transformers); + if (transformers.length == 0) { + return NOPTransformer.nopTransformer(); + } + return new ChainedTransformer(transformers); + } + + /** + * Create a new Transformer that calls each transformer in turn, passing the + * result into the next transformer. The ordering is that of the iterator() + * method on the collection. + * + * @param the object type + * @param transformers a collection of transformers to chain + * @return the chained transformer + * @throws NullPointerException if the transformers collection is null + * @throws NullPointerException if any transformer in the collection is null + */ + @SuppressWarnings("unchecked") + public static Transformer chainedTransformer( + final Collection> transformers) { + if (transformers == null) { + throw new NullPointerException("Transformer collection must not be null"); + } + if (transformers.size() == 0) { + return NOPTransformer.nopTransformer(); + } + // convert to array like this to guarantee iterator() ordering + final Transformer[] cmds = transformers.toArray(new Transformer[transformers.size()]); + FunctorUtils.validate(cmds); + return new ChainedTransformer(false, cmds); + } + + /** + * Hidden constructor for the use by the static factory methods. + * + * @param clone if {@code true} the input argument will be cloned + * @param transformers the transformers to chain, no nulls + */ + private ChainedTransformer(final boolean clone, final Transformer[] transformers) { + super(); + iTransformers = clone ? FunctorUtils.copy(transformers) : transformers; + } + + /** + * Constructor that performs no validation. + * Use chainedTransformer if you want that. + * + * @param transformers the transformers to chain, copied, no nulls + */ + @SafeVarargs + public ChainedTransformer(final Transformer... transformers) { + this(true, transformers); + } + + /** + * Transforms the input to result via each decorated transformer + * + * @param object the input object passed to the first transformer + * @return the transformed result + */ + public T transform(T object) { + for (final Transformer iTransformer : iTransformers) { + object = iTransformer.transform(object); + } + return object; + } + + /** + * Gets the transformers. + * + * @return a copy of the transformers + * @since 3.1 + */ + public Transformer[] getTransformers() { + return FunctorUtils.copy(iTransformers); + } + +} diff --git a/src/org/apache/commons/collections4/functors/CloneTransformer.java b/src/org/apache/commons/collections4/functors/CloneTransformer.java new file mode 100644 index 0000000..783f36e --- /dev/null +++ b/src/org/apache/commons/collections4/functors/CloneTransformer.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that returns a clone of the input object. + *

          + * Clone is performed using PrototypeFactory.prototypeFactory(input).create(). + *

          + * WARNING: from v4.1 onwards this class will not be serializable anymore + * in order to prevent potential remote code execution exploits. Please refer to + * COLLECTIONS-580 + * for more details. + * + * @since 3.0 + * @version $Id: CloneTransformer.java 1714262 2015-11-13 20:08:45Z tn $ + */ +public class CloneTransformer implements Transformer { + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") // the singleton instance works for all types + public static final Transformer INSTANCE = new CloneTransformer(); + + /** + * Factory returning the singleton instance. + * + * @param the type of the objects to be cloned + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") // the singleton instance works for all types + public static Transformer cloneTransformer() { + return INSTANCE; + } + + /** + * Constructor. + */ + private CloneTransformer() { + super(); + } + + /** + * Transforms the input to result by cloning it. + * + * @param input the input object to transform + * @return the transformed result + */ + @Override + public T transform(final T input) { + if (input == null) { + return null; + } + return PrototypeFactory.prototypeFactory(input).create(); + } + +} diff --git a/src/org/apache/commons/collections4/functors/ClosureTransformer.java b/src/org/apache/commons/collections4/functors/ClosureTransformer.java new file mode 100644 index 0000000..5f4fa31 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ClosureTransformer.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that calls a Closure using the input object + * and then returns the input. + * + * @since 3.0 + * @version $Id: ClosureTransformer.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ClosureTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 478466901448617286L; + + /** The closure to wrap */ + private final Closure iClosure; + + /** + * Factory method that performs validation. + * + * @param the type of the object to transform + * @param closure the closure to call, not null + * @return the closure transformer + * @throws NullPointerException if the closure is null + */ + public static Transformer closureTransformer(final Closure closure) { + if (closure == null) { + throw new NullPointerException("Closure must not be null"); + } + return new ClosureTransformer(closure); + } + + /** + * Constructor that performs no validation. + * Use closureTransformer if you want that. + * + * @param closure the closure to call, not null + */ + public ClosureTransformer(final Closure closure) { + super(); + iClosure = closure; + } + + /** + * Transforms the input to result by executing a closure. + * + * @param input the input object to transform + * @return the transformed result + */ + public T transform(final T input) { + iClosure.execute(input); + return input; + } + + /** + * Gets the closure. + * + * @return the closure + * @since 3.1 + */ + public Closure getClosure() { + return iClosure; + } + +} diff --git a/src/org/apache/commons/collections4/functors/ComparatorPredicate.java b/src/org/apache/commons/collections4/functors/ComparatorPredicate.java new file mode 100644 index 0000000..8f98193 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ComparatorPredicate.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; +import java.util.Comparator; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate that compares the input object with the one stored in the predicate using a comparator. + * In addition, the comparator result can be evaluated in accordance to a supplied criterion value. + * + * In order to demonstrate the use of the predicate, the following variables are declared: + * + *
          + * Integer ONE = Integer.valueOf(1);
          + * Integer TWO = Integer.valueOf(2);
          + *
          + * Comparator comparator = new Comparator() {
          + *
          + *     public int compare(Object first, Object second) {
          + *         return ((Integer) second) - ((Integer) first);
          + *     }
          + *
          + * };
          + * 
          + * + * Using the declared variables, the ComparatorPredicate can be used used in the + * following way: + * + *
          + * ComparatorPredicate.comparatorPredicate(ONE, comparator).evaluate(TWO);
          + * 
          + * + * The input variable TWO in compared to the stored variable ONE using + * the supplied comparator. This is the default usage of the predicate and will return + * true if the underlying comparator returns 0. In addition to the default + * usage of the predicate, it is possible to evaluate the comparator's result in several ways. The + * following {@link Criterion} enumeration values are provided by the predicate: + *

          + * + *
            + *
          • EQUAL
          • + *
          • GREATER
          • + *
          • GREATER_OR_EQUAL
          • + *
          • LESS
          • + *
          • LESS_OR_EQUAL
          • + *
          + * + * The following examples demonstrates how these constants can be used in order to manipulate the + * evaluation of a comparator result. + * + *
          + * ComparatorPredicate.comparatorPredicate(ONE, comparator,ComparatorPredicate.Criterion.GREATER).evaluate(TWO);
          + * 
          + * + * The input variable TWO is compared to the stored variable ONE using the supplied comparator + * using the GREATER evaluation criterion constant. This instructs the predicate to + * return true if the comparator returns a value greater than 0. + * + * @since 4.0 + * @version $Id: ComparatorPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ComparatorPredicate implements Predicate, Serializable { + + private static final long serialVersionUID = -1863209236504077399L; + + public enum Criterion { + EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL, + } + + // Instance variables: + + /** The internal object to compare with */ + private final T object; + + /** The comparator to use for comparison */ + private final Comparator comparator; + + /** The comparison evaluation criterion to use */ + private final Criterion criterion; + + /** + * Factory to create the comparator predicate + * + * @param the type that the predicate queries + * @param object the object to compare to + * @param comparator the comparator to use for comparison + * @return the predicate + * @throws NullPointerException if comparator is null + */ + public static Predicate comparatorPredicate(final T object, final Comparator comparator) { + return comparatorPredicate(object, comparator, Criterion.EQUAL); + } + + /** + * Factory to create the comparator predicate + * + * @param the type that the predicate queries + * @param object the object to compare to + * @param comparator the comparator to use for comparison + * @param criterion the criterion to use to evaluate comparison + * @return the predicate + * @throws NullPointerException if comparator or criterion is null + */ + public static Predicate comparatorPredicate(final T object, final Comparator comparator, + final Criterion criterion) { + if (comparator == null) { + throw new NullPointerException("Comparator must not be null."); + } + if (criterion == null) { + throw new NullPointerException("Criterion must not be null."); + } + return new ComparatorPredicate(object, comparator, criterion); + } + + /** + * Constructor that performs no validation. + * Use comparatorPredicate if you want that. + * + * @param object the object to compare to + * @param comparator the comparator to use for comparison + * @param criterion the criterion to use to evaluate comparison + */ + public ComparatorPredicate(final T object, final Comparator comparator, final Criterion criterion) { + super(); + this.object = object; + this.comparator = comparator; + this.criterion = criterion; + } + + /** + * Evaluates the predicate. The predicate evaluates to true in the following cases: + * + *
            + *
          • comparator.compare(object, input) == 0 && criterion == EQUAL
          • + *
          • comparator.compare(object, input) < 0 && criterion == LESS
          • + *
          • comparator.compare(object, input) > 0 && criterion == GREATER
          • + *
          • comparator.compare(object, input) >= 0 && criterion == GREATER_OR_EQUAL
          • + *
          • comparator.compare(object, input) <= 0 && criterion == LESS_OR_EQUAL
          • + *
          + * + * @see org.apache.commons.collections4.Predicate#evaluate(java.lang.Object) + * @see java.util.Comparator#compare(java.lang.Object first, java.lang.Object second) + * + * @param target the target object to compare to + * @return {@code true} if the comparison succeeds according to the selected criterion + * @throws IllegalStateException if the criterion is invalid (really not possible) + */ + public boolean evaluate(final T target) { + + boolean result = false; + final int comparison = comparator.compare(object, target); + switch (criterion) { + case EQUAL: + result = comparison == 0; + break; + case GREATER: + result = comparison > 0; + break; + case LESS: + result = comparison < 0; + break; + case GREATER_OR_EQUAL: + result = comparison >= 0; + break; + case LESS_OR_EQUAL: + result = comparison <= 0; + break; + default: + throw new IllegalStateException("The current criterion '" + criterion + "' is invalid."); + } + + return result; + } +} diff --git a/src/org/apache/commons/collections4/functors/ConstantFactory.java b/src/org/apache/commons/collections4/functors/ConstantFactory.java new file mode 100644 index 0000000..d38ce31 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ConstantFactory.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Factory; + +/** + * Factory implementation that returns the same constant each time. + *

          + * No check is made that the object is immutable. In general, only immutable + * objects should use the constant factory. Mutable objects should + * use the prototype factory. + * + * @since 3.0 + * @version $Id: ConstantFactory.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public class ConstantFactory implements Factory, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -3520677225766901240L; + + /** Returns null each time */ + @SuppressWarnings("rawtypes") // The null factory works for all object types + public static final Factory NULL_INSTANCE = new ConstantFactory(null); + + /** The closures to call in turn */ + private final T iConstant; + + /** + * Factory method that performs validation. + * + * @param the type of the constant + * @param constantToReturn the constant object to return each time in the factory + * @return the constant factory. + */ + @SuppressWarnings("unchecked") // The null factory works for all object types + public static Factory constantFactory(final T constantToReturn) { + if (constantToReturn == null) { + return (Factory) NULL_INSTANCE; + } + return new ConstantFactory(constantToReturn); + } + + /** + * Constructor that performs no validation. + * Use constantFactory if you want that. + * + * @param constantToReturn the constant to return each time + */ + public ConstantFactory(final T constantToReturn) { + super(); + iConstant = constantToReturn; + } + + /** + * Always return constant. + * + * @return the stored constant value + */ + public T create() { + return iConstant; + } + + /** + * Gets the constant. + * + * @return the constant + * @since 3.1 + */ + public T getConstant() { + return iConstant; + } + +} diff --git a/src/org/apache/commons/collections4/functors/ConstantTransformer.java b/src/org/apache/commons/collections4/functors/ConstantTransformer.java new file mode 100644 index 0000000..b740c92 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ConstantTransformer.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that returns the same constant each time. + *

          + * No check is made that the object is immutable. In general, only immutable + * objects should use the constant factory. Mutable objects should + * use the prototype factory. + * + * @since 3.0 + * @version $Id: ConstantTransformer.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public class ConstantTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 6374440726369055124L; + + /** Returns null each time */ + @SuppressWarnings("rawtypes") + public static final Transformer NULL_INSTANCE = new ConstantTransformer(null); + + /** The closures to call in turn */ + private final O iConstant; + + /** + * Get a typed null instance. + * + * @param the input type + * @param the output type + * @return Transformer that always returns null. + */ + @SuppressWarnings("unchecked") // The null transformer works for all object types + public static Transformer nullTransformer() { + return (Transformer) NULL_INSTANCE; + } + + /** + * Transformer method that performs validation. + * + * @param the input type + * @param the output type + * @param constantToReturn the constant object to return each time in the factory + * @return the constant factory. + */ + public static Transformer constantTransformer(final O constantToReturn) { + if (constantToReturn == null) { + return nullTransformer(); + } + return new ConstantTransformer(constantToReturn); + } + + /** + * Constructor that performs no validation. + * Use constantTransformer if you want that. + * + * @param constantToReturn the constant to return each time + */ + public ConstantTransformer(final O constantToReturn) { + super(); + iConstant = constantToReturn; + } + + /** + * Transforms the input by ignoring it and returning the stored constant instead. + * + * @param input the input object which is ignored + * @return the stored constant + */ + public O transform(final I input) { + return iConstant; + } + + /** + * Gets the constant. + * + * @return the constant + * @since 3.1 + */ + public O getConstant() { + return iConstant; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof ConstantTransformer == false) { + return false; + } + final Object otherConstant = ((ConstantTransformer) obj).getConstant(); + return otherConstant == getConstant() || otherConstant != null && otherConstant.equals(getConstant()); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = "ConstantTransformer".hashCode() << 2; + if (getConstant() != null) { + result |= getConstant().hashCode(); + } + return result; + } +} diff --git a/src/org/apache/commons/collections4/functors/DefaultEquator.java b/src/org/apache/commons/collections4/functors/DefaultEquator.java new file mode 100644 index 0000000..a27e278 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/DefaultEquator.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Equator; + +/** + * Default {@link Equator} implementation. + * + * @param the types of object this {@link Equator} can evaluate. + * @since 4.0 + * @version $Id: DefaultEquator.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public class DefaultEquator implements Equator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 825802648423525485L; + + /** Static instance */ + @SuppressWarnings("rawtypes") // the static instance works for all types + public static final DefaultEquator INSTANCE = new DefaultEquator(); + + /** + * Hashcode used for null objects. + */ + public static final int HASHCODE_NULL = -1; + + /** + * Factory returning the typed singleton instance. + * + * @param the object type + * @return the singleton instance + */ + @SuppressWarnings("unchecked") // the static instance works for all types + public static DefaultEquator defaultEquator() { + return (DefaultEquator) DefaultEquator.INSTANCE; + } + + /** + * Restricted constructor. + */ + private DefaultEquator() { + super(); + } + + /** + * {@inheritDoc} Delegates to {@link Object#equals(Object)}. + */ + public boolean equate(final T o1, final T o2) { + return o1 == o2 || o1 != null && o1.equals(o2); + } + + /** + * {@inheritDoc} + * + * @return o.hashCode() if o is non- + * null, else {@link #HASHCODE_NULL}. + */ + public int hash(final T o) { + return o == null ? HASHCODE_NULL : o.hashCode(); + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/EqualPredicate.java b/src/org/apache/commons/collections4/functors/EqualPredicate.java new file mode 100644 index 0000000..761eb76 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/EqualPredicate.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Equator; +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if the input is the same object + * as the one stored in this predicate by equals. + * + * @since 3.0 + * @version $Id: EqualPredicate.java 1683576 2015-06-04 15:23:56Z tn $ + */ +public final class EqualPredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 5633766978029907089L; + + /** The value to compare to */ + private final T iValue; + + /** The equator to use for comparison */ + private final Equator equator; + + /** + * Factory to create the predicate. + * + * @param the type that the predicate queries + * @param object the object to compare to + * @return the predicate + */ + public static Predicate equalPredicate(final T object) { + if (object == null) { + return NullPredicate.nullPredicate(); + } + return new EqualPredicate(object); + } + + /** + * Factory to create the identity predicate. + * + * @param the type that the predicate queries + * @param object the object to compare to + * @param equator the equator to use for comparison + * @return the predicate + * @since 4.0 + */ + public static Predicate equalPredicate(final T object, final Equator equator) { + if (object == null) { + return NullPredicate.nullPredicate(); + } + return new EqualPredicate(object, equator); + } + + /** + * Constructor that performs no validation. + * Use equalPredicate if you want that. + * + * @param object the object to compare to + */ + public EqualPredicate(final T object) { + // do not use the DefaultEquator to keep backwards compatibility + // the DefaultEquator returns also true if the two object references are equal + this(object, null); + } + + /** + * Constructor that performs no validation. + * Use equalPredicate if you want that. + * + * @param object the object to compare to + * @param equator the equator to use for comparison + * @since 4.0 + */ + public EqualPredicate(final T object, final Equator equator) { + super(); + iValue = object; + this.equator = equator; + } + + /** + * Evaluates the predicate returning true if the input equals the stored value. + * + * @param object the input object + * @return true if input object equals stored value + */ + public boolean evaluate(final T object) { + if (equator != null) { + return equator.equate(iValue, object); + } else { + return iValue.equals(object); + } + } + + /** + * Gets the value. + * + * @return the value + * @since 3.1 + */ + public Object getValue() { + return iValue; + } + +} diff --git a/src/org/apache/commons/collections4/functors/ExceptionClosure.java b/src/org/apache/commons/collections4/functors/ExceptionClosure.java new file mode 100644 index 0000000..d1659ec --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ExceptionClosure.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.FunctorException; + +/** + * Closure implementation that always throws an exception. + * + * @since 3.0 + * @version $Id: ExceptionClosure.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class ExceptionClosure implements Closure, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7179106032121985545L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") // the static instance works for all types + public static final Closure INSTANCE = new ExceptionClosure(); + + /** + * Factory returning the singleton instance. + * + * @param the type that the closure acts on + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") // the static instance works for all types + public static Closure exceptionClosure() { + return (Closure) INSTANCE; + } + + /** + * Restricted constructor. + */ + private ExceptionClosure() { + super(); + } + + /** + * Always throw an exception. + * + * @param input the input object + * @throws FunctorException always + */ + public void execute(final E input) { + throw new FunctorException("ExceptionClosure invoked"); + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/ExceptionFactory.java b/src/org/apache/commons/collections4/functors/ExceptionFactory.java new file mode 100644 index 0000000..6656b8d --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ExceptionFactory.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.FunctorException; + +/** + * Factory implementation that always throws an exception. + * + * @since 3.0 + * @version $Id: ExceptionFactory.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class ExceptionFactory implements Factory, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7179106032121985545L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") // the static instance works for all types + public static final Factory INSTANCE = new ExceptionFactory(); + + /** + * Factory returning the singleton instance. + * + * @param the type the factory creates + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") // the static instance works for all types + public static Factory exceptionFactory() { + return (Factory) INSTANCE; + } + + /** + * Restricted constructor. + */ + private ExceptionFactory() { + super(); + } + + /** + * Always throws an exception. + * + * @return never + * @throws FunctorException always + */ + public T create() { + throw new FunctorException("ExceptionFactory invoked"); + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/ExceptionPredicate.java b/src/org/apache/commons/collections4/functors/ExceptionPredicate.java new file mode 100644 index 0000000..f352505 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ExceptionPredicate.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.FunctorException; +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that always throws an exception. + * + * @since 3.0 + * @version $Id: ExceptionPredicate.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class ExceptionPredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7179106032121985545L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") // the static instance works for all types + public static final Predicate INSTANCE = new ExceptionPredicate(); + + /** + * Factory returning the singleton instance. + * + * @param the object type + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") // the static instance works for all types + public static Predicate exceptionPredicate() { + return (Predicate) INSTANCE; + } + + /** + * Restricted constructor. + */ + private ExceptionPredicate() { + super(); + } + + /** + * Evaluates the predicate always throwing an exception. + * + * @param object the input object + * @return never + * @throws FunctorException always + */ + public boolean evaluate(final T object) { + throw new FunctorException("ExceptionPredicate invoked"); + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/ExceptionTransformer.java b/src/org/apache/commons/collections4/functors/ExceptionTransformer.java new file mode 100644 index 0000000..52ca329 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ExceptionTransformer.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.FunctorException; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that always throws an exception. + * + * @since 3.0 + * @version $Id: ExceptionTransformer.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class ExceptionTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7179106032121985545L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") // the static instance works for all types + public static final Transformer INSTANCE = new ExceptionTransformer(); + + /** + * Factory returning the singleton instance. + * + * @param the input type + * @param the output type + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") // the static instance works for all types + public static Transformer exceptionTransformer() { + return (Transformer) INSTANCE; + } + + /** + * Restricted constructor. + */ + private ExceptionTransformer() { + super(); + } + + /** + * Transforms the input to result by cloning it. + * + * @param input the input object to transform + * @return never + * @throws FunctorException always + */ + public O transform(final I input) { + throw new FunctorException("ExceptionTransformer invoked"); + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/FactoryTransformer.java b/src/org/apache/commons/collections4/functors/FactoryTransformer.java new file mode 100644 index 0000000..c5929fd --- /dev/null +++ b/src/org/apache/commons/collections4/functors/FactoryTransformer.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that calls a Factory and returns the result. + * + * @since 3.0 + * @version $Id: FactoryTransformer.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class FactoryTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -6817674502475353160L; + + /** The factory to wrap */ + private final Factory iFactory; + + /** + * Factory method that performs validation. + * + * @param the input type + * @param the output type + * @param factory the factory to call, not null + * @return the factory transformer + * @throws NullPointerException if the factory is null + */ + public static Transformer factoryTransformer(final Factory factory) { + if (factory == null) { + throw new NullPointerException("Factory must not be null"); + } + return new FactoryTransformer(factory); + } + + /** + * Constructor that performs no validation. + * Use factoryTransformer if you want that. + * + * @param factory the factory to call, not null + */ + public FactoryTransformer(final Factory factory) { + super(); + iFactory = factory; + } + + /** + * Transforms the input by ignoring the input and returning the result of + * calling the decorated factory. + * + * @param input the input object to transform + * @return the transformed result + */ + public O transform(final I input) { + return iFactory.create(); + } + + /** + * Gets the factory. + * + * @return the factory + * @since 3.1 + */ + public Factory getFactory() { + return iFactory; + } + +} diff --git a/src/org/apache/commons/collections4/functors/FalsePredicate.java b/src/org/apache/commons/collections4/functors/FalsePredicate.java new file mode 100644 index 0000000..a09e83a --- /dev/null +++ b/src/org/apache/commons/collections4/functors/FalsePredicate.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that always returns false. + * + * @since 3.0 + * @version $Id: FalsePredicate.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class FalsePredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7533784454832764388L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") // the static instance works for all types + public static final Predicate INSTANCE = new FalsePredicate(); + + /** + * Get a typed instance. + * + * @param the type that the predicate queries + * @return the singleton instance + * @since 4.0 + */ + @SuppressWarnings("unchecked") // the static instance works for all types + public static Predicate falsePredicate() { + return (Predicate) INSTANCE; + } + + /** + * Restricted constructor. + */ + private FalsePredicate() { + super(); + } + + /** + * Evaluates the predicate returning false always. + * + * @param object the input object + * @return false always + */ + public boolean evaluate(final T object) { + return false; + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/ForClosure.java b/src/org/apache/commons/collections4/functors/ForClosure.java new file mode 100644 index 0000000..0f8c45e --- /dev/null +++ b/src/org/apache/commons/collections4/functors/ForClosure.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import org.apache.commons.collections4.Closure; + +/** + * Closure implementation that calls another closure n times, like a for loop. + *

          + * WARNING: from v4.1 onwards this class will not be serializable anymore + * in order to prevent potential remote code execution exploits. Please refer to + * COLLECTIONS-580 + * for more details. + * + * @since 3.0 + * @version $Id: ForClosure.java 1714262 2015-11-13 20:08:45Z tn $ + */ +public class ForClosure implements Closure { + + /** The number of times to loop */ + private final int iCount; + /** The closure to call */ + private final Closure iClosure; + + /** + * Factory method that performs validation. + *

          + * A null closure or zero count returns the NOPClosure. + * A count of one returns the specified closure. + * + * @param the type that the closure acts on + * @param count the number of times to execute the closure + * @param closure the closure to execute, not null + * @return the for closure + */ + @SuppressWarnings("unchecked") + public static Closure forClosure(final int count, final Closure closure) { + if (count <= 0 || closure == null) { + return NOPClosure.nopClosure(); + } + if (count == 1) { + return (Closure) closure; + } + return new ForClosure(count, closure); + } + + /** + * Constructor that performs no validation. + * Use forClosure if you want that. + * + * @param count the number of times to execute the closure + * @param closure the closure to execute, not null + */ + public ForClosure(final int count, final Closure closure) { + super(); + iCount = count; + iClosure = closure; + } + + /** + * Executes the closure count times. + * + * @param input the input object + */ + @Override + public void execute(final E input) { + for (int i = 0; i < iCount; i++) { + iClosure.execute(input); + } + } + + /** + * Gets the closure. + * + * @return the closure + * @since 3.1 + */ + public Closure getClosure() { + return iClosure; + } + + /** + * Gets the count. + * + * @return the count + * @since 3.1 + */ + public int getCount() { + return iCount; + } + +} diff --git a/src/org/apache/commons/collections4/functors/FunctorUtils.java b/src/org/apache/commons/collections4/functors/FunctorUtils.java new file mode 100644 index 0000000..4136744 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/FunctorUtils.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.util.Collection; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.Transformer; + +/** + * Internal utilities for functors. + * + * @since 3.0 + * @version $Id: FunctorUtils.java 1686855 2015-06-22 13:00:27Z tn $ + */ +class FunctorUtils { + + /** + * Restricted constructor. + */ + private FunctorUtils() { + super(); + } + + /** + * Clone the predicates to ensure that the internal reference can't be messed with. + * Due to the {@link Predicate#evaluate(T)} method, Predicate is + * able to be coerced to Predicate without casting issues. + * + * @param predicates the predicates to copy + * @return the cloned predicates + */ + @SuppressWarnings("unchecked") + static Predicate[] copy(final Predicate... predicates) { + if (predicates == null) { + return null; + } + return (Predicate[]) predicates.clone(); + } + + /** + * A very simple method that coerces Predicate to Predicate. + * Due to the {@link Predicate#evaluate(T)} method, Predicate is + * able to be coerced to Predicate without casting issues. + *

          This method exists + * simply as centralised documentation and atomic unchecked warning + * suppression. + * + * @param the type of object the returned predicate should "accept" + * @param predicate the predicate to coerce. + * @return the coerced predicate. + */ + @SuppressWarnings("unchecked") + static Predicate coerce(final Predicate predicate) { + return (Predicate) predicate; + } + + /** + * Validate the predicates to ensure that all is well. + * + * @param predicates the predicates to validate + */ + static void validate(final Predicate... predicates) { + if (predicates == null) { + throw new NullPointerException("The predicate array must not be null"); + } + for (int i = 0; i < predicates.length; i++) { + if (predicates[i] == null) { + throw new NullPointerException( + "The predicate array must not contain a null predicate, index " + i + " was null"); + } + } + } + + /** + * Validate the predicates to ensure that all is well. + * + * @param predicates the predicates to validate + * @return predicate array + */ + static Predicate[] validate(final Collection> predicates) { + if (predicates == null) { + throw new NullPointerException("The predicate collection must not be null"); + } + // convert to array like this to guarantee iterator() ordering + @SuppressWarnings("unchecked") // OK + final Predicate[] preds = new Predicate[predicates.size()]; + int i = 0; + for (final Predicate predicate : predicates) { + preds[i] = predicate; + if (preds[i] == null) { + throw new NullPointerException( + "The predicate collection must not contain a null predicate, index " + i + " was null"); + } + i++; + } + return preds; + } + + /** + * Clone the closures to ensure that the internal reference can't be messed with. + * + * @param closures the closures to copy + * @return the cloned closures + */ + @SuppressWarnings("unchecked") + static Closure[] copy(final Closure... closures) { + if (closures == null) { + return null; + } + return (Closure[]) closures.clone(); + } + + /** + * Validate the closures to ensure that all is well. + * + * @param closures the closures to validate + */ + static void validate(final Closure... closures) { + if (closures == null) { + throw new NullPointerException("The closure array must not be null"); + } + for (int i = 0; i < closures.length; i++) { + if (closures[i] == null) { + throw new NullPointerException( + "The closure array must not contain a null closure, index " + i + " was null"); + } + } + } + + /** + * A very simple method that coerces Closure to Closure. + *

          This method exists + * simply as centralised documentation and atomic unchecked warning + * suppression. + * + * @param the type of object the returned closure should "accept" + * @param closure the closure to coerce. + * @return the coerced closure. + */ + @SuppressWarnings("unchecked") + static Closure coerce(final Closure closure) { + return (Closure) closure; + } + + /** + * Copy method + * + * @param transformers the transformers to copy + * @return a clone of the transformers + */ + @SuppressWarnings("unchecked") + static Transformer[] copy(final Transformer... transformers) { + if (transformers == null) { + return null; + } + return (Transformer[]) transformers.clone(); + } + + /** + * Validate method + * + * @param transformers the transformers to validate + */ + static void validate(final Transformer... transformers) { + if (transformers == null) { + throw new NullPointerException("The transformer array must not be null"); + } + for (int i = 0; i < transformers.length; i++) { + if (transformers[i] == null) { + throw new NullPointerException( + "The transformer array must not contain a null transformer, index " + i + " was null"); + } + } + } + + /** + * A very simple method that coerces Transformer to Transformer. + *

          This method exists + * simply as centralised documentation and atomic unchecked warning + * suppression. + * + * @param the type of object the returned transformer should "accept" + * @param transformer the transformer to coerce. + * @return the coerced transformer. + */ + @SuppressWarnings("unchecked") + static Transformer coerce(final Transformer transformer) { + return (Transformer) transformer; + } + +} diff --git a/src/org/apache/commons/collections4/functors/IdentityPredicate.java b/src/org/apache/commons/collections4/functors/IdentityPredicate.java new file mode 100644 index 0000000..b3d66b6 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/IdentityPredicate.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if the input is the same object + * as the one stored in this predicate. + * + * @since 3.0 + * @version $Id: IdentityPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class IdentityPredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -89901658494523293L; + + /** The value to compare to */ + private final T iValue; + + /** + * Factory to create the identity predicate. + * + * @param the type that the predicate queries + * @param object the object to compare to + * @return the predicate + */ + public static Predicate identityPredicate(final T object) { + if (object == null) { + return NullPredicate.nullPredicate(); + } + return new IdentityPredicate(object); + } + + /** + * Constructor that performs no validation. + * Use identityPredicate if you want that. + * + * @param object the object to compare to + */ + public IdentityPredicate(final T object) { + super(); + iValue = object; + } + + /** + * Evaluates the predicate returning true if the input object is identical to + * the stored object. + * + * @param object the input object + * @return true if input is the same object as the stored value + */ + public boolean evaluate(final T object) { + return iValue == object; + } + + /** + * Gets the value. + * + * @return the value + * @since 3.1 + */ + public T getValue() { + return iValue; + } + +} diff --git a/src/org/apache/commons/collections4/functors/IfClosure.java b/src/org/apache/commons/collections4/functors/IfClosure.java new file mode 100644 index 0000000..ce98a18 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/IfClosure.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.Predicate; + +/** + * Closure implementation acts as an if statement calling one or other closure + * based on a predicate. + * + * @since 3.0 + * @version $Id: IfClosure.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class IfClosure implements Closure, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 3518477308466486130L; + + /** The test */ + private final Predicate iPredicate; + /** The closure to use if true */ + private final Closure iTrueClosure; + /** The closure to use if false */ + private final Closure iFalseClosure; + + /** + * Factory method that performs validation. + *

          + * This factory creates a closure that performs no action when + * the predicate is false. + * + * @param the type that the closure acts on + * @param predicate predicate to switch on + * @param trueClosure closure used if true + * @return the if closure + * @throws NullPointerException if either argument is null + * @since 3.2 + */ + public static Closure ifClosure(final Predicate predicate, final Closure trueClosure) { + return IfClosure.ifClosure(predicate, trueClosure, NOPClosure.nopClosure()); + } + + /** + * Factory method that performs validation. + * + * @param the type that the closure acts on + * @param predicate predicate to switch on + * @param trueClosure closure used if true + * @param falseClosure closure used if false + * @return the if closure + * @throws NullPointerException if any argument is null + */ + public static Closure ifClosure(final Predicate predicate, + final Closure trueClosure, + final Closure falseClosure) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + if (trueClosure == null || falseClosure == null) { + throw new NullPointerException("Closures must not be null"); + } + return new IfClosure(predicate, trueClosure, falseClosure); + } + + /** + * Constructor that performs no validation. + * Use ifClosure if you want that. + *

          + * This constructor creates a closure that performs no action when + * the predicate is false. + * + * @param predicate predicate to switch on, not null + * @param trueClosure closure used if true, not null + * @since 3.2 + */ + public IfClosure(final Predicate predicate, final Closure trueClosure) { + this(predicate, trueClosure, NOPClosure.nopClosure()); + } + + /** + * Constructor that performs no validation. + * Use ifClosure if you want that. + * + * @param predicate predicate to switch on, not null + * @param trueClosure closure used if true, not null + * @param falseClosure closure used if false, not null + */ + public IfClosure(final Predicate predicate, final Closure trueClosure, + final Closure falseClosure) { + super(); + iPredicate = predicate; + iTrueClosure = trueClosure; + iFalseClosure = falseClosure; + } + + /** + * Executes the true or false closure according to the result of the predicate. + * + * @param input the input object + */ + public void execute(final E input) { + if (iPredicate.evaluate(input)) { + iTrueClosure.execute(input); + } else { + iFalseClosure.execute(input); + } + } + + /** + * Gets the predicate. + * + * @return the predicate + * @since 3.1 + */ + public Predicate getPredicate() { + return iPredicate; + } + + /** + * Gets the closure called when true. + * + * @return the closure + * @since 3.1 + */ + public Closure getTrueClosure() { + return iTrueClosure; + } + + /** + * Gets the closure called when false. + * + * @return the closure + * @since 3.1 + */ + public Closure getFalseClosure() { + return iFalseClosure; + } + +} diff --git a/src/org/apache/commons/collections4/functors/IfTransformer.java b/src/org/apache/commons/collections4/functors/IfTransformer.java new file mode 100644 index 0000000..f5a12dd --- /dev/null +++ b/src/org/apache/commons/collections4/functors/IfTransformer.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that will call one of two closures based on whether a predicate evaluates + * as true or false. + * + * @param The input type for the transformer + * @param The output type for the transformer + * + * @since 4.1 + * @version $Id: IfTransformer.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class IfTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 8069309411242014252L; + + /** The test */ + private final Predicate iPredicate; + /** The transformer to use if true */ + private final Transformer iTrueTransformer; + /** The transformer to use if false */ + private final Transformer iFalseTransformer; + + /** + * Factory method that performs validation. + * + * @param input type for the transformer + * @param output type for the transformer + * @param predicate predicate to switch on + * @param trueTransformer transformer used if true + * @param falseTransformer transformer used if false + * @return the if transformer + * @throws NullPointerException if either argument is null + */ + public static Transformer ifTransformer(final Predicate predicate, + final Transformer trueTransformer, + final Transformer falseTransformer) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + if (trueTransformer == null || falseTransformer == null) { + throw new NullPointerException("Transformers must not be null"); + } + + return new IfTransformer(predicate, trueTransformer, falseTransformer); + } + + /** + * Factory method that performs validation. + *

          + * This factory creates a transformer that just returns the input object when + * the predicate is false. + * + * @param input and output type for the transformer + * @param predicate predicate to switch on + * @param trueTransformer transformer used if true + * @return the if transformer + * @throws NullPointerException if either argument is null + */ + public static Transformer ifTransformer( + final Predicate predicate, + final Transformer trueTransformer) { + + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + if (trueTransformer == null) { + throw new NullPointerException("Transformer must not be null"); + } + + return new IfTransformer(predicate, trueTransformer, NOPTransformer.nopTransformer()); + } + + /** + * Constructor that performs no validation. + * Use the static factory method ifTransformer if you want that. + * + * @param predicate predicate to switch on, not null + * @param trueTransformer transformer used if true, not null + * @param falseTransformer transformer used if false, not null + */ + public IfTransformer(final Predicate predicate, + final Transformer trueTransformer, + final Transformer falseTransformer) { + + super(); + iPredicate = predicate; + iTrueTransformer = trueTransformer; + iFalseTransformer = falseTransformer; + } + + /** + * Transforms the input using the true or false transformer based to the result of the predicate. + * + * @param input the input object to transform + * @return the transformed result + */ + public O transform(final I input) { + if(iPredicate.evaluate(input)){ + return iTrueTransformer.transform(input); + } else { + return iFalseTransformer.transform(input); + } + } + + /** + * Gets the predicate. + * + * @return the predicate + */ + public Predicate getPredicate(){ + return iPredicate; + } + + /** + * Gets the transformer used when true. + * + * @return the transformer + */ + public Transformer getTrueTransformer() { + return iTrueTransformer; + } + + /** + * Gets the transformer used when false. + * + * @return the transformer + */ + public Transformer getFalseTransformer() { + return iFalseTransformer; + } +} diff --git a/src/org/apache/commons/collections4/functors/InstanceofPredicate.java b/src/org/apache/commons/collections4/functors/InstanceofPredicate.java new file mode 100644 index 0000000..a5bf5ee --- /dev/null +++ b/src/org/apache/commons/collections4/functors/InstanceofPredicate.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if the input is an instanceof + * the type stored in this predicate. + * + * @since 3.0 + * @version $Id: InstanceofPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class InstanceofPredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -6682656911025165584L; + + /** The type to compare to */ + private final Class iType; + + /** + * Factory to create the identity predicate. + * + * @param type the type to check for, may not be null + * @return the predicate + * @throws NullPointerException if the class is null + */ + public static Predicate instanceOfPredicate(final Class type) { + if (type == null) { + throw new NullPointerException("The type to check instanceof must not be null"); + } + return new InstanceofPredicate(type); + } + + /** + * Constructor that performs no validation. + * Use instanceOfPredicate if you want that. + * + * @param type the type to check for + */ + public InstanceofPredicate(final Class type) { + super(); + iType = type; + } + + /** + * Evaluates the predicate returning true if the input object is of the correct type. + * + * @param object the input object + * @return true if input is of stored type + */ + public boolean evaluate(final Object object) { + return iType.isInstance(object); + } + + /** + * Gets the type to compare to. + * + * @return the type + * @since 3.1 + */ + public Class getType() { + return iType; + } + +} diff --git a/src/org/apache/commons/collections4/functors/InstantiateFactory.java b/src/org/apache/commons/collections4/functors/InstantiateFactory.java new file mode 100644 index 0000000..9375422 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/InstantiateFactory.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.FunctorException; + +/** + * Factory implementation that creates a new object instance by reflection. + *

          + * WARNING: from v4.1 onwards this class will not be serializable anymore + * in order to prevent potential remote code execution exploits. Please refer to + * COLLECTIONS-580 + * for more details. + * + * @since 3.0 + * @version $Id: InstantiateFactory.java 1714262 2015-11-13 20:08:45Z tn $ + */ +public class InstantiateFactory implements Factory { + + /** The class to create */ + private final Class iClassToInstantiate; + /** The constructor parameter types */ + private final Class[] iParamTypes; + /** The constructor arguments */ + private final Object[] iArgs; + /** The constructor */ + private transient Constructor iConstructor = null; + + /** + * Factory method that performs validation. + * + * @param the type the factory creates + * @param classToInstantiate the class to instantiate, not null + * @param paramTypes the constructor parameter types, cloned + * @param args the constructor arguments, cloned + * @return a new instantiate factory + * @throws NullPointerException if classToInstantiate is null + * @throws IllegalArgumentException if paramTypes does not match args + */ + public static Factory instantiateFactory(final Class classToInstantiate, + final Class[] paramTypes, + final Object[] args) { + if (classToInstantiate == null) { + throw new NullPointerException("Class to instantiate must not be null"); + } + if (paramTypes == null && args != null + || paramTypes != null && args == null + || paramTypes != null && args != null && paramTypes.length != args.length) { + throw new IllegalArgumentException("Parameter types must match the arguments"); + } + + if (paramTypes == null || paramTypes.length == 0) { + return new InstantiateFactory(classToInstantiate); + } + return new InstantiateFactory(classToInstantiate, paramTypes, args); + } + + /** + * Constructor that performs no validation. + * Use instantiateFactory if you want that. + * + * @param classToInstantiate the class to instantiate + */ + public InstantiateFactory(final Class classToInstantiate) { + super(); + iClassToInstantiate = classToInstantiate; + iParamTypes = null; + iArgs = null; + findConstructor(); + } + + /** + * Constructor that performs no validation. + * Use instantiateFactory if you want that. + * + * @param classToInstantiate the class to instantiate + * @param paramTypes the constructor parameter types, cloned + * @param args the constructor arguments, cloned + */ + public InstantiateFactory(final Class classToInstantiate, final Class[] paramTypes, final Object[] args) { + super(); + iClassToInstantiate = classToInstantiate; + iParamTypes = paramTypes.clone(); + iArgs = args.clone(); + findConstructor(); + } + + /** + * Find the Constructor for the class specified. + */ + private void findConstructor() { + try { + iConstructor = iClassToInstantiate.getConstructor(iParamTypes); + } catch (final NoSuchMethodException ex) { + throw new IllegalArgumentException("InstantiateFactory: The constructor must exist and be public "); + } + } + + /** + * Creates an object using the stored constructor. + * + * @return the new object + */ + @Override + public T create() { + // needed for post-serialization + if (iConstructor == null) { + findConstructor(); + } + + try { + return iConstructor.newInstance(iArgs); + } catch (final InstantiationException ex) { + throw new FunctorException("InstantiateFactory: InstantiationException", ex); + } catch (final IllegalAccessException ex) { + throw new FunctorException("InstantiateFactory: Constructor must be public", ex); + } catch (final InvocationTargetException ex) { + throw new FunctorException("InstantiateFactory: Constructor threw an exception", ex); + } + } + +} diff --git a/src/org/apache/commons/collections4/functors/InstantiateTransformer.java b/src/org/apache/commons/collections4/functors/InstantiateTransformer.java new file mode 100644 index 0000000..7fabe0f --- /dev/null +++ b/src/org/apache/commons/collections4/functors/InstantiateTransformer.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import org.apache.commons.collections4.FunctorException; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that creates a new object instance by reflection. + *

          + * WARNING: from v4.1 onwards this class will not be serializable anymore + * in order to prevent potential remote code execution exploits. Please refer to + * COLLECTIONS-580 + * for more details. + * + * @since 3.0 + * @version $Id: InstantiateTransformer.java 1714262 2015-11-13 20:08:45Z tn $ + */ +public class InstantiateTransformer implements Transformer, T> { + + /** Singleton instance that uses the no arg constructor */ + @SuppressWarnings("rawtypes") + private static final Transformer NO_ARG_INSTANCE = new InstantiateTransformer(); + + /** The constructor parameter types */ + private final Class[] iParamTypes; + /** The constructor arguments */ + private final Object[] iArgs; + + /** + * Get a typed no-arg instance. + * + * @param the type of the objects to be created + * @return Transformer, T> + */ + @SuppressWarnings("unchecked") + public static Transformer, T> instantiateTransformer() { + return NO_ARG_INSTANCE; + } + + /** + * Transformer method that performs validation. + * + * @param the type of the objects to be created + * @param paramTypes the constructor parameter types + * @param args the constructor arguments + * @return an instantiate transformer + * @throws IllegalArgumentException if paramTypes does not match args + */ + public static Transformer, T> instantiateTransformer(final Class[] paramTypes, + final Object[] args) { + if (((paramTypes == null) && (args != null)) + || ((paramTypes != null) && (args == null)) + || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) { + throw new IllegalArgumentException("Parameter types must match the arguments"); + } + + if (paramTypes == null || paramTypes.length == 0) { + return new InstantiateTransformer(); + } + return new InstantiateTransformer(paramTypes, args); + } + + /** + * Constructor for no arg instance. + */ + private InstantiateTransformer() { + super(); + iParamTypes = null; + iArgs = null; + } + + /** + * Constructor that performs no validation. + * Use instantiateTransformer if you want that. + *

          + * Note: from 4.0, the input parameters will be cloned + * + * @param paramTypes the constructor parameter types + * @param args the constructor arguments + */ + public InstantiateTransformer(final Class[] paramTypes, final Object[] args) { + super(); + iParamTypes = paramTypes != null ? paramTypes.clone() : null; + iArgs = args != null ? args.clone() : null; + } + + /** + * Transforms the input Class object to a result by instantiation. + * + * @param input the input object to transform + * @return the transformed result + */ + @Override + public T transform(final Class input) { + try { + if (input == null) { + throw new FunctorException( + "InstantiateTransformer: Input object was not an instanceof Class, it was a null object"); + } + final Constructor con = input.getConstructor(iParamTypes); + return con.newInstance(iArgs); + } catch (final NoSuchMethodException ex) { + throw new FunctorException("InstantiateTransformer: The constructor must exist and be public "); + } catch (final InstantiationException ex) { + throw new FunctorException("InstantiateTransformer: InstantiationException", ex); + } catch (final IllegalAccessException ex) { + throw new FunctorException("InstantiateTransformer: Constructor must be public", ex); + } catch (final InvocationTargetException ex) { + throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex); + } + } + +} diff --git a/src/org/apache/commons/collections4/functors/InvokerTransformer.java b/src/org/apache/commons/collections4/functors/InvokerTransformer.java new file mode 100644 index 0000000..3241000 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/InvokerTransformer.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.commons.collections4.FunctorException; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that creates a new object instance by reflection. + *

          + * WARNING: from v4.1 onwards this class will not be serializable anymore + * in order to prevent potential remote code execution exploits. Please refer to + * COLLECTIONS-580 + * for more details. + * + * @since 3.0 + * @version $Id: InvokerTransformer.java 1714262 2015-11-13 20:08:45Z tn $ + */ +public class InvokerTransformer implements Transformer { + + /** The method name to call */ + private final String iMethodName; + /** The array of reflection parameter types */ + private final Class[] iParamTypes; + /** The array of reflection arguments */ + private final Object[] iArgs; + + /** + * Gets an instance of this transformer calling a specific method with no arguments. + * + * @param the input type + * @param the output type + * @param methodName the method name to call + * @return an invoker transformer + * @throws NullPointerException if methodName is null + * @since 3.1 + */ + public static Transformer invokerTransformer(final String methodName) { + if (methodName == null) { + throw new NullPointerException("The method to invoke must not be null"); + } + return new InvokerTransformer(methodName); + } + + /** + * Gets an instance of this transformer calling a specific method with specific values. + * + * @param the input type + * @param the output type + * @param methodName the method name to call + * @param paramTypes the parameter types of the method + * @param args the arguments to pass to the method + * @return an invoker transformer + * @throws NullPointerException if methodName is null + * @throws IllegalArgumentException if paramTypes does not match args + */ + public static Transformer invokerTransformer(final String methodName, final Class[] paramTypes, + final Object[] args) { + if (methodName == null) { + throw new NullPointerException("The method to invoke must not be null"); + } + if (((paramTypes == null) && (args != null)) + || ((paramTypes != null) && (args == null)) + || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) { + throw new IllegalArgumentException("The parameter types must match the arguments"); + } + if (paramTypes == null || paramTypes.length == 0) { + return new InvokerTransformer(methodName); + } + return new InvokerTransformer(methodName, paramTypes, args); + } + + /** + * Constructor for no arg instance. + * + * @param methodName the method to call + */ + private InvokerTransformer(final String methodName) { + super(); + iMethodName = methodName; + iParamTypes = null; + iArgs = null; + } + + /** + * Constructor that performs no validation. + * Use invokerTransformer if you want that. + *

          + * Note: from 4.0, the input parameters will be cloned + * + * @param methodName the method to call + * @param paramTypes the constructor parameter types + * @param args the constructor arguments + */ + public InvokerTransformer(final String methodName, final Class[] paramTypes, final Object[] args) { + super(); + iMethodName = methodName; + iParamTypes = paramTypes != null ? paramTypes.clone() : null; + iArgs = args != null ? args.clone() : null; + } + + /** + * Transforms the input to result by invoking a method on the input. + * + * @param input the input object to transform + * @return the transformed result, null if null input + */ + @Override + @SuppressWarnings("unchecked") + public O transform(final Object input) { + if (input == null) { + return null; + } + try { + final Class cls = input.getClass(); + final Method method = cls.getMethod(iMethodName, iParamTypes); + return (O) method.invoke(input, iArgs); + } catch (final NoSuchMethodException ex) { + throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + + input.getClass() + "' does not exist"); + } catch (final IllegalAccessException ex) { + throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + + input.getClass() + "' cannot be accessed"); + } catch (final InvocationTargetException ex) { + throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + + input.getClass() + "' threw an exception", ex); + } + } + +} diff --git a/src/org/apache/commons/collections4/functors/MapTransformer.java b/src/org/apache/commons/collections4/functors/MapTransformer.java new file mode 100644 index 0000000..7eed02c --- /dev/null +++ b/src/org/apache/commons/collections4/functors/MapTransformer.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that returns the value held in a specified map + * using the input parameter as a key. + * + * @since 3.0 + * @version $Id: MapTransformer.java 1476582 2013-04-27 14:13:54Z tn $ + */ +public final class MapTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 862391807045468939L; + + /** The map of data to lookup in */ + private final Map iMap; + + /** + * Factory to create the transformer. + *

          + * If the map is null, a transformer that always returns null is returned. + * + * @param the input type + * @param the output type + * @param map the map, not cloned + * @return the transformer + */ + public static Transformer mapTransformer(final Map map) { + if (map == null) { + return ConstantTransformer.nullTransformer(); + } + return new MapTransformer(map); + } + + /** + * Constructor that performs no validation. + * Use mapTransformer if you want that. + * + * @param map the map to use for lookup, not cloned + */ + private MapTransformer(final Map map) { + super(); + iMap = map; + } + + /** + * Transforms the input to result by looking it up in a Map. + * + * @param input the input object to transform + * @return the transformed result + */ + public O transform(final I input) { + return iMap.get(input); + } + + /** + * Gets the map to lookup in. + * + * @return the map + * @since 3.1 + */ + public Map getMap() { + return iMap; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NOPClosure.java b/src/org/apache/commons/collections4/functors/NOPClosure.java new file mode 100644 index 0000000..1a30912 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NOPClosure.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Closure; + +/** + * Closure implementation that does nothing. + * + * @since 3.0 + * @version $Id: NOPClosure.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class NOPClosure implements Closure, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 3518477308466486130L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") + public static final Closure INSTANCE = new NOPClosure(); + + /** + * Factory returning the singleton instance. + * + * @param the type that the closure acts on + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public static Closure nopClosure() { + return (Closure) INSTANCE; + } + + /** + * Constructor. + */ + private NOPClosure() { + super(); + } + + /** + * Do nothing. + * + * @param input the input object + */ + public void execute(final E input) { + // do nothing + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NOPTransformer.java b/src/org/apache/commons/collections4/functors/NOPTransformer.java new file mode 100644 index 0000000..4c1d726 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NOPTransformer.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that does nothing. + * + * @since 3.0 + * @version $Id: NOPTransformer.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public class NOPTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 2133891748318574490L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") + public static final Transformer INSTANCE = new NOPTransformer(); + + /** + * Factory returning the singleton instance. + * + * @param the input/output type + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public static Transformer nopTransformer() { + return (Transformer) INSTANCE; + } + + /** + * Constructor. + */ + private NOPTransformer() { + super(); + } + + /** + * Transforms the input to result by doing nothing. + * + * @param input the input object to transform + * @return the transformed result which is the input + */ + public T transform(final T input) { + return input; + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NonePredicate.java b/src/org/apache/commons/collections4/functors/NonePredicate.java new file mode 100644 index 0000000..bc3aebc --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NonePredicate.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.util.Collection; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if none of the + * predicates return true. + * If the array of predicates is empty, then this predicate returns true. + *

          + * NOTE: In versions prior to 3.2 an array size of zero or one + * threw an exception. + * + * @since 3.0 + * @version $Id: NonePredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class NonePredicate extends AbstractQuantifierPredicate { + + /** Serial version UID */ + private static final long serialVersionUID = 2007613066565892961L; + + /** + * Factory to create the predicate. + *

          + * If the array is size zero, the predicate always returns true. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the any predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + @SafeVarargs + public static Predicate nonePredicate(final Predicate... predicates) { + FunctorUtils.validate(predicates); + if (predicates.length == 0) { + return TruePredicate.truePredicate(); + } + return new NonePredicate(FunctorUtils.copy(predicates)); + } + + /** + * Factory to create the predicate. + *

          + * If the collection is size zero, the predicate always returns true. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the one predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + public static Predicate nonePredicate(final Collection> predicates) { + final Predicate[] preds = FunctorUtils.validate(predicates); + if (preds.length == 0) { + return TruePredicate.truePredicate(); + } + return new NonePredicate(preds); + } + + /** + * Constructor that performs no validation. + * Use nonePredicate if you want that. + * + * @param predicates the predicates to check, not cloned, not null + */ + @SafeVarargs + public NonePredicate(final Predicate... predicates) { + super(predicates); + } + + /** + * Evaluates the predicate returning false if any stored predicate returns false. + * + * @param object the input object + * @return true if none of decorated predicates return true + */ + public boolean evaluate(final T object) { + for (final Predicate iPredicate : iPredicates) { + if (iPredicate.evaluate(object)) { + return false; + } + } + return true; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NotNullPredicate.java b/src/org/apache/commons/collections4/functors/NotNullPredicate.java new file mode 100644 index 0000000..05a1b9d --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NotNullPredicate.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if the input is not null. + * + * @since 3.0 + * @version $Id: NotNullPredicate.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class NotNullPredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7533784454832764388L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") + public static final Predicate INSTANCE = new NotNullPredicate(); + + /** + * Factory returning the singleton instance. + * + * @param the type that the predicate queries + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public static Predicate notNullPredicate() { + return (Predicate) INSTANCE; + } + + /** + * Restricted constructor. + */ + private NotNullPredicate() { + super(); + } + + /** + * Evaluates the predicate returning true if the object does not equal null. + * + * @param object the object to evaluate + * @return true if not null + */ + public boolean evaluate(final T object) { + return object != null; + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NotPredicate.java b/src/org/apache/commons/collections4/functors/NotPredicate.java new file mode 100644 index 0000000..6a3924f --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NotPredicate.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns the opposite of the decorated predicate. + * + * @since 3.0 + * @version $Id: NotPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class NotPredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -2654603322338049674L; + + /** The predicate to decorate */ + private final Predicate iPredicate; + + /** + * Factory to create the not predicate. + * + * @param the type that the predicate queries + * @param predicate the predicate to decorate, not null + * @return the predicate + * @throws NullPointerException if the predicate is null + */ + public static Predicate notPredicate(final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new NotPredicate(predicate); + } + + /** + * Constructor that performs no validation. + * Use notPredicate if you want that. + * + * @param predicate the predicate to call after the null check + */ + public NotPredicate(final Predicate predicate) { + super(); + iPredicate = predicate; + } + + /** + * Evaluates the predicate returning the opposite to the stored predicate. + * + * @param object the input object + * @return true if predicate returns false + */ + public boolean evaluate(final T object) { + return !iPredicate.evaluate(object); + } + + /** + * Gets the predicate being decorated. + * + * @return the predicate as the only element in an array + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public Predicate[] getPredicates() { + return new Predicate[] {iPredicate}; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NullIsExceptionPredicate.java b/src/org/apache/commons/collections4/functors/NullIsExceptionPredicate.java new file mode 100644 index 0000000..77c3459 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NullIsExceptionPredicate.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.FunctorException; +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that throws an exception if the input is null. + * + * @since 3.0 + * @version $Id: NullIsExceptionPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class NullIsExceptionPredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 3243449850504576071L; + + /** The predicate to decorate */ + private final Predicate iPredicate; + + /** + * Factory to create the null exception predicate. + * + * @param the type that the predicate queries + * @param predicate the predicate to decorate, not null + * @return the predicate + * @throws NullPointerException if the predicate is null + */ + public static Predicate nullIsExceptionPredicate(final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new NullIsExceptionPredicate(predicate); + } + + /** + * Constructor that performs no validation. + * Use nullIsExceptionPredicate if you want that. + * + * @param predicate the predicate to call after the null check + */ + public NullIsExceptionPredicate(final Predicate predicate) { + super(); + iPredicate = predicate; + } + + /** + * Evaluates the predicate returning the result of the decorated predicate + * once a null check is performed. + * + * @param object the input object + * @return true if decorated predicate returns true + * @throws FunctorException if input is null + */ + public boolean evaluate(final T object) { + if (object == null) { + throw new FunctorException("Input Object must not be null"); + } + return iPredicate.evaluate(object); + } + + /** + * Gets the predicate being decorated. + * + * @return the predicate as the only element in an array + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public Predicate[] getPredicates() { + return new Predicate[] { iPredicate }; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NullIsFalsePredicate.java b/src/org/apache/commons/collections4/functors/NullIsFalsePredicate.java new file mode 100644 index 0000000..69eefaa --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NullIsFalsePredicate.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns false if the input is null. + * + * @since 3.0 + * @version $Id: NullIsFalsePredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class NullIsFalsePredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -2997501534564735525L; + + /** The predicate to decorate */ + private final Predicate iPredicate; + + /** + * Factory to create the null false predicate. + * + * @param the type that the predicate queries + * @param predicate the predicate to decorate, not null + * @return the predicate + * @throws NullPointerException if the predicate is null + */ + public static Predicate nullIsFalsePredicate(final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new NullIsFalsePredicate(predicate); + } + + /** + * Constructor that performs no validation. + * Use nullIsFalsePredicate if you want that. + * + * @param predicate the predicate to call after the null check + */ + public NullIsFalsePredicate(final Predicate predicate) { + super(); + iPredicate = predicate; + } + + /** + * Evaluates the predicate returning the result of the decorated predicate + * once a null check is performed. + * + * @param object the input object + * @return true if decorated predicate returns true, false if input is null + */ + public boolean evaluate(final T object) { + if (object == null) { + return false; + } + return iPredicate.evaluate(object); + } + + /** + * Gets the predicate being decorated. + * + * @return the predicate as the only element in an array + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public Predicate[] getPredicates() { + return new Predicate[] { iPredicate }; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NullIsTruePredicate.java b/src/org/apache/commons/collections4/functors/NullIsTruePredicate.java new file mode 100644 index 0000000..a5e06be --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NullIsTruePredicate.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if the input is null. + * + * @since 3.0 + * @version $Id: NullIsTruePredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class NullIsTruePredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -7625133768987126273L; + + /** The predicate to decorate */ + private final Predicate iPredicate; + + /** + * Factory to create the null true predicate. + * + * @param the type that the predicate queries + * @param predicate the predicate to decorate, not null + * @return the predicate + * @throws NullPointerException if the predicate is null + */ + public static Predicate nullIsTruePredicate(final Predicate predicate) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new NullIsTruePredicate(predicate); + } + + /** + * Constructor that performs no validation. + * Use nullIsTruePredicate if you want that. + * + * @param predicate the predicate to call after the null check + */ + public NullIsTruePredicate(final Predicate predicate) { + super(); + iPredicate = predicate; + } + + /** + * Evaluates the predicate returning the result of the decorated predicate + * once a null check is performed. + * + * @param object the input object + * @return true if decorated predicate returns true or input is null + */ + public boolean evaluate(final T object) { + if (object == null) { + return true; + } + return iPredicate.evaluate(object); + } + + /** + * Gets the predicate being decorated. + * + * @return the predicate as the only element in an array + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public Predicate[] getPredicates() { + return new Predicate[] { iPredicate }; + } + +} diff --git a/src/org/apache/commons/collections4/functors/NullPredicate.java b/src/org/apache/commons/collections4/functors/NullPredicate.java new file mode 100644 index 0000000..5924bb6 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/NullPredicate.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if the input is null. + * + * @since 3.0 + * @version $Id: NullPredicate.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class NullPredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7533784454832764388L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") + public static final Predicate INSTANCE = new NullPredicate(); + + /** + * Factory returning the singleton instance. + * + * @param the type that the predicate queries + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public static Predicate nullPredicate() { + return (Predicate) INSTANCE; + } + + /** + * Restricted constructor. + */ + private NullPredicate() { + super(); + } + + /** + * Evaluates the predicate returning true if the input is null. + * + * @param object the input object + * @return true if input is null + */ + public boolean evaluate(final T object) { + return object == null; + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/OnePredicate.java b/src/org/apache/commons/collections4/functors/OnePredicate.java new file mode 100644 index 0000000..a9c0fbb --- /dev/null +++ b/src/org/apache/commons/collections4/functors/OnePredicate.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.util.Collection; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if only one of the + * predicates return true. + * If the array of predicates is empty, then this predicate returns false. + *

          + * NOTE: In versions prior to 3.2 an array size of zero or one + * threw an exception. + * + * @since 3.0 + * @version $Id: OnePredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class OnePredicate extends AbstractQuantifierPredicate { + + /** Serial version UID */ + private static final long serialVersionUID = -8125389089924745785L; + + /** + * Factory to create the predicate. + *

          + * If the array is size zero, the predicate always returns false. + * If the array is size one, then that predicate is returned. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the any predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + @SuppressWarnings("unchecked") + public static Predicate onePredicate(final Predicate... predicates) { + FunctorUtils.validate(predicates); + if (predicates.length == 0) { + return FalsePredicate.falsePredicate(); + } + if (predicates.length == 1) { + return (Predicate) predicates[0]; + } + return new OnePredicate(FunctorUtils.copy(predicates)); + } + + /** + * Factory to create the predicate. + * + * @param the type that the predicate queries + * @param predicates the predicates to check, cloned, not null + * @return the one predicate + * @throws NullPointerException if the predicates array is null + * @throws NullPointerException if any predicate in the array is null + */ + public static Predicate onePredicate(final Collection> predicates) { + final Predicate[] preds = FunctorUtils.validate(predicates); + return new OnePredicate(preds); + } + + /** + * Constructor that performs no validation. + * Use onePredicate if you want that. + * + * @param predicates the predicates to check, not cloned, not null + */ + @SafeVarargs + public OnePredicate(final Predicate... predicates) { + super(predicates); + } + + /** + * Evaluates the predicate returning true if only one decorated predicate + * returns true. + * + * @param object the input object + * @return true if only one decorated predicate returns true + */ + public boolean evaluate(final T object) { + boolean match = false; + for (final Predicate iPredicate : iPredicates) { + if (iPredicate.evaluate(object)) { + if (match) { + return false; + } + match = true; + } + } + return match; + } + +} diff --git a/src/org/apache/commons/collections4/functors/OrPredicate.java b/src/org/apache/commons/collections4/functors/OrPredicate.java new file mode 100644 index 0000000..3a89a1f --- /dev/null +++ b/src/org/apache/commons/collections4/functors/OrPredicate.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true if either of the predicates return true. + * + * @since 3.0 + * @version $Id: OrPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class OrPredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -8791518325735182855L; + + /** The array of predicates to call */ + private final Predicate iPredicate1; + /** The array of predicates to call */ + private final Predicate iPredicate2; + + /** + * Factory to create the predicate. + * + * @param the type that the predicate queries + * @param predicate1 the first predicate to check, not null + * @param predicate2 the second predicate to check, not null + * @return the and predicate + * @throws NullPointerException if either predicate is null + */ + public static Predicate orPredicate(final Predicate predicate1, + final Predicate predicate2) { + if (predicate1 == null || predicate2 == null) { + throw new NullPointerException("Predicate must not be null"); + } + return new OrPredicate(predicate1, predicate2); + } + + /** + * Constructor that performs no validation. + * Use orPredicate if you want that. + * + * @param predicate1 the first predicate to check, not null + * @param predicate2 the second predicate to check, not null + */ + public OrPredicate(final Predicate predicate1, final Predicate predicate2) { + super(); + iPredicate1 = predicate1; + iPredicate2 = predicate2; + } + + /** + * Evaluates the predicate returning true if either predicate returns true. + * + * @param object the input object + * @return true if either decorated predicate returns true + */ + public boolean evaluate(final T object) { + return iPredicate1.evaluate(object) || iPredicate2.evaluate(object); + } + + /** + * Gets the two predicates being decorated as an array. + * + * @return the predicates + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public Predicate[] getPredicates() { + return new Predicate[] {iPredicate1, iPredicate2}; + } + +} diff --git a/src/org/apache/commons/collections4/functors/PredicateDecorator.java b/src/org/apache/commons/collections4/functors/PredicateDecorator.java new file mode 100644 index 0000000..19917ac --- /dev/null +++ b/src/org/apache/commons/collections4/functors/PredicateDecorator.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import org.apache.commons.collections4.Predicate; + +/** + * Defines a predicate that decorates one or more other predicates. + *

          + * This interface enables tools to access the decorated predicates. + * + * @since 3.1 + * @version $Id: PredicateDecorator.java 1477798 2013-04-30 19:49:02Z tn $ + */ +public interface PredicateDecorator extends Predicate { + + /** + * Gets the predicates being decorated as an array. + *

          + * The array may be the internal data structure of the predicate and thus + * should not be altered. + * + * @return the predicates being decorated + */ + Predicate[] getPredicates(); + +} diff --git a/src/org/apache/commons/collections4/functors/PredicateTransformer.java b/src/org/apache/commons/collections4/functors/PredicateTransformer.java new file mode 100644 index 0000000..058816b --- /dev/null +++ b/src/org/apache/commons/collections4/functors/PredicateTransformer.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that calls a Predicate using the input object + * and then returns the result. + * + * @since 3.0 + * @version $Id: PredicateTransformer.java 1477798 2013-04-30 19:49:02Z tn $ + */ +public class PredicateTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 5278818408044349346L; + + /** The closure to wrap */ + private final Predicate iPredicate; + + /** + * Factory method that performs validation. + * + * @param the input type + * @param predicate the predicate to call, not null + * @return the predicate transformer + * @throws IllegalArgumentException if the predicate is null + */ + public static Transformer predicateTransformer(final Predicate predicate) { + if (predicate == null) { + throw new IllegalArgumentException("Predicate must not be null"); + } + return new PredicateTransformer(predicate); + } + + /** + * Constructor that performs no validation. + * Use predicateTransformer if you want that. + * + * @param predicate the predicate to call, not null + */ + public PredicateTransformer(final Predicate predicate) { + super(); + iPredicate = predicate; + } + + /** + * Transforms the input to result by calling a predicate. + * + * @param input the input object to transform + * @return the transformed result + */ + public Boolean transform(final T input) { + return Boolean.valueOf(iPredicate.evaluate(input)); + } + + /** + * Gets the predicate. + * + * @return the predicate + * @since 3.1 + */ + public Predicate getPredicate() { + return iPredicate; + } + +} diff --git a/src/org/apache/commons/collections4/functors/PrototypeFactory.java b/src/org/apache/commons/collections4/functors/PrototypeFactory.java new file mode 100644 index 0000000..b5d1676 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/PrototypeFactory.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.FunctorException; + +/** + * Factory implementation that creates a new instance each time based on a prototype. + *

          + * WARNING: from v4.1 onwards {@link Factory} instances returned by + * {@link #prototypeFactory(Object)} will not be serializable anymore in order + * to prevent potential remote code execution exploits. Please refer to + * COLLECTIONS-580 + * for more details. + * + * @since 3.0 + * @version $Id: PrototypeFactory.java 1714262 2015-11-13 20:08:45Z tn $ + */ +public class PrototypeFactory { + + /** + * Factory method that performs validation. + *

          + * Creates a Factory that will return a clone of the same prototype object + * each time the factory is used. The prototype will be cloned using one of these + * techniques (in order): + *

            + *
          • public clone method + *
          • public copy constructor + *
          • serialization clone + *
              + * + * @param the type the factory creates + * @param prototype the object to clone each time in the factory + * @return the prototype factory, or a {@link ConstantFactory#NULL_INSTANCE} if + * the {@code prototype} is {@code null} + * @throws IllegalArgumentException if the prototype cannot be cloned + */ + @SuppressWarnings("unchecked") + public static Factory prototypeFactory(final T prototype) { + if (prototype == null) { + return ConstantFactory.constantFactory(null); + } + try { + final Method method = prototype.getClass().getMethod("clone", (Class[]) null); + return new PrototypeCloneFactory(prototype, method); + + } catch (final NoSuchMethodException ex) { + try { + prototype.getClass().getConstructor(new Class[] { prototype.getClass() }); + return new InstantiateFactory( + (Class) prototype.getClass(), + new Class[] { prototype.getClass() }, + new Object[] { prototype }); + } catch (final NoSuchMethodException ex2) { + if (prototype instanceof Serializable) { + return (Factory) new PrototypeSerializationFactory((Serializable) prototype); + } + } + } + throw new IllegalArgumentException("The prototype must be cloneable via a public clone method"); + } + + /** + * Restricted constructor. + */ + private PrototypeFactory() { + super(); + } + + // PrototypeCloneFactory + //----------------------------------------------------------------------- + /** + * PrototypeCloneFactory creates objects by copying a prototype using the clone method. + */ + static class PrototypeCloneFactory implements Factory { + + /** The object to clone each time */ + private final T iPrototype; + /** The method used to clone */ + private transient Method iCloneMethod; + + /** + * Constructor to store prototype. + */ + private PrototypeCloneFactory(final T prototype, final Method method) { + super(); + iPrototype = prototype; + iCloneMethod = method; + } + + /** + * Find the Clone method for the class specified. + */ + private void findCloneMethod() { + try { + iCloneMethod = iPrototype.getClass().getMethod("clone", (Class[]) null); + } catch (final NoSuchMethodException ex) { + throw new IllegalArgumentException("PrototypeCloneFactory: The clone method must exist and be public "); + } + } + + /** + * Creates an object by calling the clone method. + * + * @return the new object + */ + @Override + @SuppressWarnings("unchecked") + public T create() { + // needed for post-serialization + if (iCloneMethod == null) { + findCloneMethod(); + } + + try { + return (T) iCloneMethod.invoke(iPrototype, (Object[]) null); + } catch (final IllegalAccessException ex) { + throw new FunctorException("PrototypeCloneFactory: Clone method must be public", ex); + } catch (final InvocationTargetException ex) { + throw new FunctorException("PrototypeCloneFactory: Clone method threw an exception", ex); + } + } + } + + // PrototypeSerializationFactory + //----------------------------------------------------------------------- + /** + * PrototypeSerializationFactory creates objects by cloning a prototype using serialization. + */ + static class PrototypeSerializationFactory implements Factory { + + /** The object to clone via serialization each time */ + private final T iPrototype; + + /** + * Constructor to store prototype + */ + private PrototypeSerializationFactory(final T prototype) { + super(); + iPrototype = prototype; + } + + /** + * Creates an object using serialization. + * + * @return the new object + */ + @Override + @SuppressWarnings("unchecked") + public T create() { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(512); + ByteArrayInputStream bais = null; + try { + final ObjectOutputStream out = new ObjectOutputStream(baos); + out.writeObject(iPrototype); + + bais = new ByteArrayInputStream(baos.toByteArray()); + final ObjectInputStream in = new ObjectInputStream(bais); + return (T) in.readObject(); + + } catch (final ClassNotFoundException ex) { + throw new FunctorException(ex); + } catch (final IOException ex) { + throw new FunctorException(ex); + } finally { + try { + if (bais != null) { + bais.close(); + } + } catch (final IOException ex) { + // ignore + } + try { + baos.close(); + } catch (final IOException ex) { + // ignore + } + } + } + } + +} diff --git a/src/org/apache/commons/collections4/functors/StringValueTransformer.java b/src/org/apache/commons/collections4/functors/StringValueTransformer.java new file mode 100644 index 0000000..f26a74c --- /dev/null +++ b/src/org/apache/commons/collections4/functors/StringValueTransformer.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation that returns the result of calling + * String.valueOf on the input object. + * + * @since 3.0 + * @version $Id: StringValueTransformer.java 1543964 2013-11-20 21:53:39Z tn $ + */ +public final class StringValueTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 7511110693171758606L; + + /** Singleton predicate instance */ + private static final Transformer INSTANCE = new StringValueTransformer(); + + /** + * Factory returning the singleton instance. + * + * @param the input type + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public static Transformer stringValueTransformer() { + return (Transformer) INSTANCE; + } + + /** + * Restricted constructor. + */ + private StringValueTransformer() { + super(); + } + + /** + * Transforms the input to result by calling String.valueOf. + * + * @param input the input object to transform + * @return the transformed result + */ + public String transform(final T input) { + return String.valueOf(input); + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/SwitchClosure.java b/src/org/apache/commons/collections4/functors/SwitchClosure.java new file mode 100644 index 0000000..b484dd7 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/SwitchClosure.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.Predicate; + +/** + * Closure implementation calls the closure whose predicate returns true, + * like a switch statement. + * + * @since 3.0 + * @version $Id: SwitchClosure.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class SwitchClosure implements Closure, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 3518477308466486130L; + + /** The tests to consider */ + private final Predicate[] iPredicates; + /** The matching closures to call */ + private final Closure[] iClosures; + /** The default closure to call if no tests match */ + private final Closure iDefault; + + /** + * Factory method that performs validation and copies the parameter arrays. + * + * @param the type that the closure acts on + * @param predicates array of predicates, cloned, no nulls + * @param closures matching array of closures, cloned, no nulls + * @param defaultClosure the closure to use if no match, null means nop + * @return the chained closure + * @throws NullPointerException if array is null + * @throws NullPointerException if any element in the array is null + * @throws IllegalArgumentException if the array lengths of predicates and closures do not match + */ + @SuppressWarnings("unchecked") + public static Closure switchClosure(final Predicate[] predicates, + final Closure[] closures, + final Closure defaultClosure) { + FunctorUtils.validate(predicates); + FunctorUtils.validate(closures); + if (predicates.length != closures.length) { + throw new IllegalArgumentException("The predicate and closure arrays must be the same size"); + } + if (predicates.length == 0) { + return (Closure) (defaultClosure == null ? NOPClosure.nopClosure(): defaultClosure); + } + return new SwitchClosure(predicates, closures, defaultClosure); + } + + /** + * Create a new Closure that calls one of the closures depending + * on the predicates. + *

              + * The Map consists of Predicate keys and Closure values. A closure + * is called if its matching predicate returns true. Each predicate is evaluated + * until one returns true. If no predicates evaluate to true, the default + * closure is called. The default closure is set in the map with a + * null key. The ordering is that of the iterator() method on the entryset + * collection of the map. + * + * @param the type that the closure acts on + * @param predicatesAndClosures a map of predicates to closures + * @return the switch closure + * @throws NullPointerException if the map is null + * @throws NullPointerException if any closure in the map is null + * @throws ClassCastException if the map elements are of the wrong type + */ + @SuppressWarnings("unchecked") + public static Closure switchClosure(final Map, Closure> predicatesAndClosures) { + if (predicatesAndClosures == null) { + throw new NullPointerException("The predicate and closure map must not be null"); + } + // convert to array like this to guarantee iterator() ordering + final Closure defaultClosure = predicatesAndClosures.remove(null); + final int size = predicatesAndClosures.size(); + if (size == 0) { + return (Closure) (defaultClosure == null ? NOPClosure.nopClosure() : defaultClosure); + } + final Closure[] closures = new Closure[size]; + final Predicate[] preds = new Predicate[size]; + int i = 0; + for (final Map.Entry, Closure> entry : predicatesAndClosures.entrySet()) { + preds[i] = entry.getKey(); + closures[i] = entry.getValue(); + i++; + } + return new SwitchClosure(false, preds, closures, defaultClosure); + } + + /** + * Hidden constructor for the use by the static factory methods. + * + * @param clone if {@code true} the input arguments will be cloned + * @param predicates array of predicates, no nulls + * @param closures matching array of closures, no nulls + * @param defaultClosure the closure to use if no match, null means nop + */ + @SuppressWarnings("unchecked") + private SwitchClosure(final boolean clone, final Predicate[] predicates, + final Closure[] closures, final Closure defaultClosure) { + super(); + iPredicates = clone ? FunctorUtils.copy(predicates) : predicates; + iClosures = clone ? FunctorUtils.copy(closures) : closures; + iDefault = (Closure) (defaultClosure == null ? NOPClosure.nopClosure() : defaultClosure); + } + + /** + * Constructor that performs no validation. + * Use switchClosure if you want that. + * + * @param predicates array of predicates, cloned, no nulls + * @param closures matching array of closures, cloned, no nulls + * @param defaultClosure the closure to use if no match, null means nop + */ + public SwitchClosure(final Predicate[] predicates, final Closure[] closures, + final Closure defaultClosure) { + this(true, predicates, closures, defaultClosure); + } + + /** + * Executes the closure whose matching predicate returns true + * + * @param input the input object + */ + public void execute(final E input) { + for (int i = 0; i < iPredicates.length; i++) { + if (iPredicates[i].evaluate(input) == true) { + iClosures[i].execute(input); + return; + } + } + iDefault.execute(input); + } + + /** + * Gets the predicates. + * + * @return a copy of the predicates + * @since 3.1 + */ + public Predicate[] getPredicates() { + return FunctorUtils.copy(iPredicates); + } + + /** + * Gets the closures. + * + * @return a copy of the closures + * @since 3.1 + */ + public Closure[] getClosures() { + return FunctorUtils.copy(iClosures); + } + + /** + * Gets the default closure. + * + * @return the default closure + * @since 3.1 + */ + public Closure getDefaultClosure() { + return iDefault; + } + +} diff --git a/src/org/apache/commons/collections4/functors/SwitchTransformer.java b/src/org/apache/commons/collections4/functors/SwitchTransformer.java new file mode 100644 index 0000000..e83f10b --- /dev/null +++ b/src/org/apache/commons/collections4/functors/SwitchTransformer.java @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.Transformer; + +/** + * Transformer implementation calls the transformer whose predicate returns true, + * like a switch statement. + * + * @since 3.0 + * @version $Id: SwitchTransformer.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class SwitchTransformer implements Transformer, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -6404460890903469332L; + + /** The tests to consider */ + private final Predicate[] iPredicates; + /** The matching transformers to call */ + private final Transformer[] iTransformers; + /** The default transformer to call if no tests match */ + private final Transformer iDefault; + + /** + * Factory method that performs validation and copies the parameter arrays. + * + * @param the input type + * @param the output type + * @param predicates array of predicates, cloned, no nulls + * @param transformers matching array of transformers, cloned, no nulls + * @param defaultTransformer the transformer to use if no match, null means return null + * @return the chained transformer + * @throws NullPointerException if array is null + * @throws NullPointerException if any element in the array is null + */ + @SuppressWarnings("unchecked") + public static Transformer switchTransformer(final Predicate[] predicates, + final Transformer[] transformers, + final Transformer defaultTransformer) { + FunctorUtils.validate(predicates); + FunctorUtils.validate(transformers); + if (predicates.length != transformers.length) { + throw new IllegalArgumentException("The predicate and transformer arrays must be the same size"); + } + if (predicates.length == 0) { + return (Transformer) (defaultTransformer == null ? ConstantTransformer.nullTransformer() : + defaultTransformer); + } + return new SwitchTransformer(predicates, transformers, defaultTransformer); + } + + /** + * Create a new Transformer that calls one of the transformers depending + * on the predicates. + *

              + * The Map consists of Predicate keys and Transformer values. A transformer + * is called if its matching predicate returns true. Each predicate is evaluated + * until one returns true. If no predicates evaluate to true, the default + * transformer is called. The default transformer is set in the map with a + * null key. The ordering is that of the iterator() method on the entryset + * collection of the map. + * + * @param the input type + * @param the output type + * @param map a map of predicates to transformers + * @return the switch transformer + * @throws NullPointerException if the map is null + * @throws NullPointerException if any transformer in the map is null + * @throws ClassCastException if the map elements are of the wrong type + */ + @SuppressWarnings("unchecked") + public static Transformer switchTransformer( + final Map, ? extends Transformer> map) { + + if (map == null) { + throw new NullPointerException("The predicate and transformer map must not be null"); + } + if (map.size() == 0) { + return ConstantTransformer.nullTransformer(); + } + // convert to array like this to guarantee iterator() ordering + final Transformer defaultTransformer = map.remove(null); + final int size = map.size(); + if (size == 0) { + return (Transformer) (defaultTransformer == null ? ConstantTransformer.nullTransformer() : + defaultTransformer); + } + final Transformer[] transformers = new Transformer[size]; + final Predicate[] preds = new Predicate[size]; + int i = 0; + for (final Map.Entry, + ? extends Transformer> entry : map.entrySet()) { + preds[i] = entry.getKey(); + transformers[i] = entry.getValue(); + i++; + } + return new SwitchTransformer(false, preds, transformers, defaultTransformer); + } + + /** + * Hidden constructor for the use by the static factory methods. + * + * @param clone if {@code true} the input arguments will be cloned + * @param predicates array of predicates, no nulls + * @param transformers matching array of transformers, no nulls + * @param defaultTransformer the transformer to use if no match, null means return null + */ + @SuppressWarnings("unchecked") + private SwitchTransformer(final boolean clone, final Predicate[] predicates, + final Transformer[] transformers, + final Transformer defaultTransformer) { + super(); + iPredicates = clone ? FunctorUtils.copy(predicates) : predicates; + iTransformers = clone ? FunctorUtils.copy(transformers) : transformers; + iDefault = (Transformer) (defaultTransformer == null ? + ConstantTransformer.nullTransformer() : defaultTransformer); + } + + /** + * Constructor that performs no validation. + * Use switchTransformer if you want that. + * + * @param predicates array of predicates, cloned, no nulls + * @param transformers matching array of transformers, cloned, no nulls + * @param defaultTransformer the transformer to use if no match, null means return null + */ + public SwitchTransformer(final Predicate[] predicates, + final Transformer[] transformers, + final Transformer defaultTransformer) { + this(true, predicates, transformers, defaultTransformer); + } + + /** + * Transforms the input to result by calling the transformer whose matching + * predicate returns true. + * + * @param input the input object to transform + * @return the transformed result + */ + public O transform(final I input) { + for (int i = 0; i < iPredicates.length; i++) { + if (iPredicates[i].evaluate(input) == true) { + return iTransformers[i].transform(input); + } + } + return iDefault.transform(input); + } + + /** + * Gets the predicates. + * + * @return a copy of the predicates + * @since 3.1 + */ + public Predicate[] getPredicates() { + return FunctorUtils.copy(iPredicates); + } + + /** + * Gets the transformers. + * + * @return a copy of the transformers + * @since 3.1 + */ + public Transformer[] getTransformers() { + return FunctorUtils.copy(iTransformers); + } + + /** + * Gets the default transformer. + * + * @return the default transformer + * @since 3.1 + */ + public Transformer getDefaultTransformer() { + return iDefault; + } + +} diff --git a/src/org/apache/commons/collections4/functors/TransformedPredicate.java b/src/org/apache/commons/collections4/functors/TransformedPredicate.java new file mode 100644 index 0000000..a19fe8b --- /dev/null +++ b/src/org/apache/commons/collections4/functors/TransformedPredicate.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.Transformer; + +/** + * Predicate implementation that transforms the given object before invoking + * another Predicate. + * + * @since 3.1 + * @version $Id: TransformedPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class TransformedPredicate implements PredicateDecorator, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -5596090919668315834L; + + /** The transformer to call */ + private final Transformer iTransformer; + + /** The predicate to call */ + private final Predicate iPredicate; + + /** + * Factory to create the predicate. + * + * @param the type that the predicate queries + * @param transformer the transformer to call + * @param predicate the predicate to call with the result of the transform + * @return the predicate + * @throws NullPointerException if the transformer or the predicate is null + */ + public static Predicate transformedPredicate(final Transformer transformer, + final Predicate predicate) { + if (transformer == null) { + throw new NullPointerException("The transformer to call must not be null"); + } + if (predicate == null) { + throw new NullPointerException("The predicate to call must not be null"); + } + return new TransformedPredicate(transformer, predicate); + } + + /** + * Constructor that performs no validation. + * Use transformedPredicate if you want that. + * + * @param transformer the transformer to use + * @param predicate the predicate to decorate + */ + public TransformedPredicate(final Transformer transformer, + final Predicate predicate) { + iTransformer = transformer; + iPredicate = predicate; + } + + /** + * Evaluates the predicate returning the result of the decorated predicate + * once the input has been transformed + * + * @param object the input object which will be transformed + * @return true if decorated predicate returns true + */ + public boolean evaluate(final T object) { + final T result = iTransformer.transform(object); + return iPredicate.evaluate(result); + } + + /** + * Gets the predicate being decorated. + * + * @return the predicate as the only element in an array + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public Predicate[] getPredicates() { + return new Predicate[] {iPredicate}; + } + + /** + * Gets the transformer in use. + * + * @return the transformer + */ + public Transformer getTransformer() { + return iTransformer; + } + +} diff --git a/src/org/apache/commons/collections4/functors/TransformerClosure.java b/src/org/apache/commons/collections4/functors/TransformerClosure.java new file mode 100644 index 0000000..77def81 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/TransformerClosure.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.Transformer; + +/** + * Closure implementation that calls a Transformer using the input object + * and ignore the result. + * + * @since 3.0 + * @version $Id: TransformerClosure.java 1477798 2013-04-30 19:49:02Z tn $ + */ +public class TransformerClosure implements Closure, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -5194992589193388969L; + + /** The transformer to wrap */ + private final Transformer iTransformer; + + /** + * Factory method that performs validation. + *

              + * A null transformer will return the NOPClosure. + * + * @param the type that the closure acts on + * @param transformer the transformer to call, null means nop + * @return the transformer closure + */ + public static Closure transformerClosure(final Transformer transformer) { + if (transformer == null) { + return NOPClosure.nopClosure(); + } + return new TransformerClosure(transformer); + } + + /** + * Constructor that performs no validation. + * Use transformerClosure if you want that. + * + * @param transformer the transformer to call, not null + */ + public TransformerClosure(final Transformer transformer) { + super(); + iTransformer = transformer; + } + + /** + * Executes the closure by calling the decorated transformer. + * + * @param input the input object + */ + public void execute(final E input) { + iTransformer.transform(input); + } + + /** + * Gets the transformer. + * + * @return the transformer + * @since 3.1 + */ + public Transformer getTransformer() { + return iTransformer; + } + +} diff --git a/src/org/apache/commons/collections4/functors/TransformerPredicate.java b/src/org/apache/commons/collections4/functors/TransformerPredicate.java new file mode 100644 index 0000000..5dc95bb --- /dev/null +++ b/src/org/apache/commons/collections4/functors/TransformerPredicate.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.FunctorException; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.Transformer; + +/** + * Predicate implementation that returns the result of a transformer. + * + * @since 3.0 + * @version $Id: TransformerPredicate.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class TransformerPredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -2407966402920578741L; + + /** The transformer to call */ + private final Transformer iTransformer; + + /** + * Factory to create the predicate. + * + * @param the type that the predicate queries + * @param transformer the transformer to decorate + * @return the predicate + * @throws NullPointerException if the transformer is null + */ + public static Predicate transformerPredicate(final Transformer transformer) { + if (transformer == null) { + throw new NullPointerException("The transformer to call must not be null"); + } + return new TransformerPredicate(transformer); + } + + /** + * Constructor that performs no validation. + * Use transformerPredicate if you want that. + * + * @param transformer the transformer to decorate + */ + public TransformerPredicate(final Transformer transformer) { + super(); + iTransformer = transformer; + } + + /** + * Evaluates the predicate returning the result of the decorated transformer. + * + * @param object the input object + * @return true if decorated transformer returns Boolean.TRUE + * @throws FunctorException if the transformer returns an invalid type + */ + public boolean evaluate(final T object) { + final Boolean result = iTransformer.transform(object); + if (result == null) { + throw new FunctorException( + "Transformer must return an instanceof Boolean, it was a null object"); + } + return result.booleanValue(); + } + + /** + * Gets the transformer. + * + * @return the transformer + * @since 3.1 + */ + public Transformer getTransformer() { + return iTransformer; + } + +} diff --git a/src/org/apache/commons/collections4/functors/TruePredicate.java b/src/org/apache/commons/collections4/functors/TruePredicate.java new file mode 100644 index 0000000..757f139 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/TruePredicate.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that always returns true. + * + * @since 3.0 + * @version $Id: TruePredicate.java 1543950 2013-11-20 21:13:35Z tn $ + */ +public final class TruePredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = 3374767158756189740L; + + /** Singleton predicate instance */ + @SuppressWarnings("rawtypes") + public static final Predicate INSTANCE = new TruePredicate(); + + /** + * Factory returning the singleton instance. + * + * @param the type that the predicate queries + * @return the singleton instance + * @since 3.1 + */ + @SuppressWarnings("unchecked") + public static Predicate truePredicate() { + return (Predicate) INSTANCE; + } + + /** + * Restricted constructor. + */ + private TruePredicate() { + super(); + } + + /** + * Evaluates the predicate returning true always. + * + * @param object the input object + * @return true always + */ + public boolean evaluate(final T object) { + return true; + } + + private Object readResolve() { + return INSTANCE; + } + +} diff --git a/src/org/apache/commons/collections4/functors/UniquePredicate.java b/src/org/apache/commons/collections4/functors/UniquePredicate.java new file mode 100644 index 0000000..64be48c --- /dev/null +++ b/src/org/apache/commons/collections4/functors/UniquePredicate.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.collections4.Predicate; + +/** + * Predicate implementation that returns true the first time an object is + * passed into the predicate. + * + * @since 3.0 + * @version $Id: UniquePredicate.java 1476582 2013-04-27 14:13:54Z tn $ + */ +public final class UniquePredicate implements Predicate, Serializable { + + /** Serial version UID */ + private static final long serialVersionUID = -3319417438027438040L; + + /** The set of previously seen objects */ + private final Set iSet = new HashSet(); + + /** + * Factory to create the predicate. + * + * @param the type that the predicate queries + * @return the predicate + * @throws IllegalArgumentException if the predicate is null + */ + public static Predicate uniquePredicate() { + return new UniquePredicate(); + } + + /** + * Constructor that performs no validation. + * Use uniquePredicate if you want that. + */ + public UniquePredicate() { + super(); + } + + /** + * Evaluates the predicate returning true if the input object hasn't been + * received yet. + * + * @param object the input object + * @return true if this is the first time the object is seen + */ + public boolean evaluate(final T object) { + return iSet.add(object); + } + +} diff --git a/src/org/apache/commons/collections4/functors/WhileClosure.java b/src/org/apache/commons/collections4/functors/WhileClosure.java new file mode 100644 index 0000000..dcf2844 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/WhileClosure.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.functors; + +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.Predicate; + +/** + * Closure implementation that executes a closure repeatedly until a condition is met, + * like a do-while or while loop. + *

              + * WARNING: from v4.1 onwards this class will not be serializable anymore + * in order to prevent potential remote code execution exploits. Please refer to + * COLLECTIONS-580 + * for more details. + * + * @since 3.0 + * @version $Id: WhileClosure.java 1714262 2015-11-13 20:08:45Z tn $ + */ +public class WhileClosure implements Closure { + + /** The test condition */ + private final Predicate iPredicate; + /** The closure to call */ + private final Closure iClosure; + /** The flag, true is a do loop, false is a while */ + private final boolean iDoLoop; + + /** + * Factory method that performs validation. + * + * @param the type that the closure acts on + * @param predicate the predicate used to evaluate when the loop terminates, not null + * @param closure the closure the execute, not null + * @param doLoop true to act as a do-while loop, always executing the closure once + * @return the while closure + * @throws NullPointerException if the predicate or closure is null + */ + public static Closure whileClosure(final Predicate predicate, + final Closure closure, final boolean doLoop) { + if (predicate == null) { + throw new NullPointerException("Predicate must not be null"); + } + if (closure == null) { + throw new NullPointerException("Closure must not be null"); + } + return new WhileClosure(predicate, closure, doLoop); + } + + /** + * Constructor that performs no validation. + * Use whileClosure if you want that. + * + * @param predicate the predicate used to evaluate when the loop terminates, not null + * @param closure the closure the execute, not null + * @param doLoop true to act as a do-while loop, always executing the closure once + */ + public WhileClosure(final Predicate predicate, final Closure closure, final boolean doLoop) { + super(); + iPredicate = predicate; + iClosure = closure; + iDoLoop = doLoop; + } + + /** + * Executes the closure until the predicate is false. + * + * @param input the input object + */ + @Override + public void execute(final E input) { + if (iDoLoop) { + iClosure.execute(input); + } + while (iPredicate.evaluate(input)) { + iClosure.execute(input); + } + } + + /** + * Gets the predicate in use. + * + * @return the predicate + * @since 3.1 + */ + public Predicate getPredicate() { + return iPredicate; + } + + /** + * Gets the closure. + * + * @return the closure + * @since 3.1 + */ + public Closure getClosure() { + return iClosure; + } + + /** + * Is the loop a do-while loop. + * + * @return true is do-while, false if while + * @since 3.1 + */ + public boolean isDoLoop() { + return iDoLoop; + } + +} diff --git a/src/org/apache/commons/collections4/functors/package-info.java b/src/org/apache/commons/collections4/functors/package-info.java new file mode 100644 index 0000000..f025519 --- /dev/null +++ b/src/org/apache/commons/collections4/functors/package-info.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the + * {@link org.apache.commons.collections4.Closure Closure}, + * {@link org.apache.commons.collections4.Predicate Predicate}, + * {@link org.apache.commons.collections4.Transformer Transformer} and + * {@link org.apache.commons.collections4.Factory Factory} interfaces. + * These provide simple callbacks for processing with collections. + *

              + * WARNING: from v4.1 onwards several unsafe classes in this package + * will not be serializable anymore in order to prevent potential remote + * code execution exploits. + *

              + * Classes considered to be unsafe are: + *

                + *
              • CloneTransformer
              • + *
              • ForClosure
              • + *
              • InstantiateFactory
              • + *
              • InstantiateTransformer
              • + *
              • InvokerTransformer
              • + *
              • PrototypeFactory$PrototypeCloneFactory
              • + *
              • PrototypeFactory$PrototypeSerializationFactory
              • + *
              • WhileClosure
              • + *
              + * + * @version $Id: package-info.java 1714262 2015-11-13 20:08:45Z tn $ + */ +package org.apache.commons.collections4.functors; diff --git a/src/org/apache/commons/collections4/iterators/AbstractEmptyIterator.java b/src/org/apache/commons/collections4/iterators/AbstractEmptyIterator.java new file mode 100644 index 0000000..8716cda --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/AbstractEmptyIterator.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.NoSuchElementException; + +/** + * Provides an implementation of an empty iterator. + * + * @since 3.1 + * @version $Id: AbstractEmptyIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +abstract class AbstractEmptyIterator { + + /** + * Constructor. + */ + protected AbstractEmptyIterator() { + super(); + } + + public boolean hasNext() { + return false; + } + + public E next() { + throw new NoSuchElementException("Iterator contains no elements"); + } + + public boolean hasPrevious() { + return false; + } + + public E previous() { + throw new NoSuchElementException("Iterator contains no elements"); + } + + public int nextIndex() { + return 0; + } + + public int previousIndex() { + return -1; + } + + public void add(final E obj) { + throw new UnsupportedOperationException("add() not supported for empty Iterator"); + } + + public void set(final E obj) { + throw new IllegalStateException("Iterator contains no elements"); + } + + public void remove() { + throw new IllegalStateException("Iterator contains no elements"); + } + + public void reset() { + // do nothing + } + +} diff --git a/src/org/apache/commons/collections4/iterators/AbstractEmptyMapIterator.java b/src/org/apache/commons/collections4/iterators/AbstractEmptyMapIterator.java new file mode 100644 index 0000000..d45798a --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/AbstractEmptyMapIterator.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +/** + * Provides an implementation of an empty map iterator. + * + * @since 4.0 + * @version $Id: AbstractEmptyMapIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public abstract class AbstractEmptyMapIterator extends AbstractEmptyIterator { + + /** + * Create a new AbstractEmptyMapIterator. + */ + public AbstractEmptyMapIterator() { + super(); + } + + public K getKey() { + throw new IllegalStateException("Iterator contains no elements"); + } + + public V getValue() { + throw new IllegalStateException("Iterator contains no elements"); + } + + public V setValue(final V value) { + throw new IllegalStateException("Iterator contains no elements"); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/AbstractIteratorDecorator.java b/src/org/apache/commons/collections4/iterators/AbstractIteratorDecorator.java new file mode 100644 index 0000000..9b030db --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/AbstractIteratorDecorator.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +/** + * Provides basic behaviour for decorating an iterator with extra functionality. + *

              + * All methods are forwarded to the decorated iterator. + * + * @since 3.0 + * @version $Id: AbstractIteratorDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractIteratorDecorator extends AbstractUntypedIteratorDecorator { + + //----------------------------------------------------------------------- + /** + * Constructor that decorates the specified iterator. + * + * @param iterator the iterator to decorate, must not be null + * @throws NullPointerException if the iterator is null + */ + protected AbstractIteratorDecorator(final Iterator iterator) { + super(iterator); + } + + /** {@inheritDoc} */ + public E next() { + return getIterator().next(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/AbstractListIteratorDecorator.java b/src/org/apache/commons/collections4/iterators/AbstractListIteratorDecorator.java new file mode 100644 index 0000000..a0771f0 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/AbstractListIteratorDecorator.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ListIterator; + +/** + * Provides basic behaviour for decorating a list iterator with extra functionality. + *

              + * All methods are forwarded to the decorated list iterator. + * + * @since 3.0 + * @version $Id: AbstractListIteratorDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class AbstractListIteratorDecorator implements ListIterator { + + /** The iterator being decorated */ + private final ListIterator iterator; + + //----------------------------------------------------------------------- + /** + * Constructor that decorates the specified iterator. + * + * @param iterator the iterator to decorate, must not be null + * @throws NullPointerException if the iterator is null + */ + public AbstractListIteratorDecorator(final ListIterator iterator) { + super(); + if (iterator == null) { + throw new NullPointerException("ListIterator must not be null"); + } + this.iterator = iterator; + } + + /** + * Gets the iterator being decorated. + * + * @return the decorated iterator + */ + protected ListIterator getListIterator() { + return iterator; + } + + //----------------------------------------------------------------------- + + /** {@inheritDoc} */ + public boolean hasNext() { + return iterator.hasNext(); + } + + /** {@inheritDoc} */ + public E next() { + return iterator.next(); + } + + /** {@inheritDoc} */ + public int nextIndex() { + return iterator.nextIndex(); + } + + /** {@inheritDoc} */ + public boolean hasPrevious() { + return iterator.hasPrevious(); + } + + /** {@inheritDoc} */ + public E previous() { + return iterator.previous(); + } + + /** {@inheritDoc} */ + public int previousIndex() { + return iterator.previousIndex(); + } + + /** {@inheritDoc} */ + public void remove() { + iterator.remove(); + } + + /** {@inheritDoc} */ + public void set(final E obj) { + iterator.set(obj); + } + + /** {@inheritDoc} */ + public void add(final E obj) { + iterator.add(obj); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/AbstractMapIteratorDecorator.java b/src/org/apache/commons/collections4/iterators/AbstractMapIteratorDecorator.java new file mode 100644 index 0000000..bc2a23f --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/AbstractMapIteratorDecorator.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import org.apache.commons.collections4.MapIterator; + +/** + * Provides basic behaviour for decorating a map iterator with extra functionality. + *

              + * All methods are forwarded to the decorated map iterator. + * + * @since 3.0 + * @version $Id: AbstractMapIteratorDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class AbstractMapIteratorDecorator implements MapIterator { + + /** The iterator being decorated */ + private final MapIterator iterator; + + //----------------------------------------------------------------------- + /** + * Constructor that decorates the specified iterator. + * + * @param iterator the iterator to decorate, must not be null + * @throws NullPointerException if the iterator is null + */ + public AbstractMapIteratorDecorator(final MapIterator iterator) { + super(); + if (iterator == null) { + throw new NullPointerException("MapIterator must not be null"); + } + this.iterator = iterator; + } + + /** + * Gets the iterator being decorated. + * + * @return the decorated iterator + */ + protected MapIterator getMapIterator() { + return iterator; + } + + //----------------------------------------------------------------------- + + /** {@inheritDoc} */ + public boolean hasNext() { + return iterator.hasNext(); + } + + /** {@inheritDoc} */ + public K next() { + return iterator.next(); + } + + /** {@inheritDoc} */ + public void remove() { + iterator.remove(); + } + + /** {@inheritDoc} */ + public K getKey() { + return iterator.getKey(); + } + + /** {@inheritDoc} */ + public V getValue() { + return iterator.getValue(); + } + + /** {@inheritDoc} */ + public V setValue(final V obj) { + return iterator.setValue(obj); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/AbstractOrderedMapIteratorDecorator.java b/src/org/apache/commons/collections4/iterators/AbstractOrderedMapIteratorDecorator.java new file mode 100644 index 0000000..d3d7489 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/AbstractOrderedMapIteratorDecorator.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import org.apache.commons.collections4.OrderedMapIterator; + +/** + * Provides basic behaviour for decorating an ordered map iterator with extra functionality. + *

              + * All methods are forwarded to the decorated map iterator. + * + * @since 3.0 + * @version $Id: AbstractOrderedMapIteratorDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class AbstractOrderedMapIteratorDecorator implements OrderedMapIterator { + + /** The iterator being decorated */ + private final OrderedMapIterator iterator; + + //----------------------------------------------------------------------- + /** + * Constructor that decorates the specified iterator. + * + * @param iterator the iterator to decorate, must not be null + * @throws NullPointerException if the iterator is null + */ + public AbstractOrderedMapIteratorDecorator(final OrderedMapIterator iterator) { + super(); + if (iterator == null) { + throw new NullPointerException("OrderedMapIterator must not be null"); + } + this.iterator = iterator; + } + + /** + * Gets the iterator being decorated. + * + * @return the decorated iterator + */ + protected OrderedMapIterator getOrderedMapIterator() { + return iterator; + } + + //----------------------------------------------------------------------- + + /** {@inheritDoc} */ + public boolean hasNext() { + return iterator.hasNext(); + } + + /** {@inheritDoc} */ + public K next() { + return iterator.next(); + } + + /** {@inheritDoc} */ + public boolean hasPrevious() { + return iterator.hasPrevious(); + } + + /** {@inheritDoc} */ + public K previous() { + return iterator.previous(); + } + + /** {@inheritDoc} */ + public void remove() { + iterator.remove(); + } + + /** {@inheritDoc} */ + public K getKey() { + return iterator.getKey(); + } + + /** {@inheritDoc} */ + public V getValue() { + return iterator.getValue(); + } + + /** {@inheritDoc} */ + public V setValue(final V obj) { + return iterator.setValue(obj); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/AbstractUntypedIteratorDecorator.java b/src/org/apache/commons/collections4/iterators/AbstractUntypedIteratorDecorator.java new file mode 100644 index 0000000..87d232f --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/AbstractUntypedIteratorDecorator.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +/** + * Provides basic behaviour for decorating an iterator with extra functionality + * without committing the generic type of the Iterator implementation. + *

              + * All methods are forwarded to the decorated iterator. + * + * @since 4.0 + * @version $Id: AbstractUntypedIteratorDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractUntypedIteratorDecorator implements Iterator { + + /** The iterator being decorated */ + private final Iterator iterator; + + /** + * Create a new AbstractUntypedIteratorDecorator. + * + * @param iterator the iterator to decorate + * @throws NullPointerException if the iterator is null + */ + protected AbstractUntypedIteratorDecorator(final Iterator iterator) { + super(); + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + this.iterator = iterator; + } + + /** + * Gets the iterator being decorated. + * + * @return the decorated iterator + */ + protected Iterator getIterator() { + return iterator; + } + + public boolean hasNext() { + return iterator.hasNext(); + } + + public void remove() { + iterator.remove(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/ArrayIterator.java b/src/org/apache/commons/collections4/iterators/ArrayIterator.java new file mode 100644 index 0000000..52ec85b --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ArrayIterator.java @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.lang.reflect.Array; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableIterator; + +/** + * Implements an {@link java.util.Iterator Iterator} over any array. + *

              + * The array can be either an array of object or of primitives. If you know + * that you have an object array, the + * {@link org.apache.commons.collections4.iterators.ObjectArrayIterator ObjectArrayIterator} + * class is a better choice, as it will perform better. + *

              + * The iterator implements a {@link #reset} method, allowing the reset of + * the iterator back to the start if required. + * + * @since 1.0 + * @version $Id: ArrayIterator.java 1494282 2013-06-18 20:09:15Z sebb $ + */ +public class ArrayIterator implements ResettableIterator { + + /** The array to iterate over */ + final Object array; + /** The start index to loop from */ + final int startIndex; + /** The end index to loop to */ + final int endIndex; + /** The current iterator index */ + int index = 0; + + // Constructors + // ---------------------------------------------------------------------- + /** + * Constructs an ArrayIterator that will iterate over the values in the + * specified array. + * + * @param array the array to iterate over. + * @throws IllegalArgumentException if array is not an array. + * @throws NullPointerException if array is null + */ + public ArrayIterator(final Object array) { + this(array, 0); + } + + /** + * Constructs an ArrayIterator that will iterate over the values in the + * specified array from a specific start index. + * + * @param array the array to iterate over. + * @param startIndex the index to start iterating at. + * @throws IllegalArgumentException if array is not an array. + * @throws NullPointerException if array is null + * @throws IndexOutOfBoundsException if the index is invalid + */ + public ArrayIterator(final Object array, final int startIndex) { + this(array, startIndex, Array.getLength(array)); + } + + /** + * Construct an ArrayIterator that will iterate over a range of values + * in the specified array. + * + * @param array the array to iterate over. + * @param startIndex the index to start iterating at. + * @param endIndex the index to finish iterating at. + * @throws IllegalArgumentException if array is not an array. + * @throws NullPointerException if array is null + * @throws IndexOutOfBoundsException if either index is invalid + */ + public ArrayIterator(final Object array, final int startIndex, final int endIndex) { + super(); + + this.array = array; + this.startIndex = startIndex; + this.endIndex = endIndex; + this.index = startIndex; + + final int len = Array.getLength(array); + checkBound(startIndex, len, "start"); + checkBound(endIndex, len, "end"); + if (endIndex < startIndex) { + throw new IllegalArgumentException("End index must not be less than start index."); + } + } + + /** + * Checks whether the index is valid or not. + * + * @param bound the index to check + * @param len the length of the array + * @param type the index type (for error messages) + * @throws IndexOutOfBoundsException if the index is invalid + */ + protected void checkBound(final int bound, final int len, final String type ) { + if (bound > len) { + throw new ArrayIndexOutOfBoundsException( + "Attempt to make an ArrayIterator that " + type + + "s beyond the end of the array. " + ); + } + if (bound < 0) { + throw new ArrayIndexOutOfBoundsException( + "Attempt to make an ArrayIterator that " + type + + "s before the start of the array. " + ); + } + } + + // Iterator interface + //----------------------------------------------------------------------- + /** + * Returns true if there are more elements to return from the array. + * + * @return true if there is a next element to return + */ + public boolean hasNext() { + return index < endIndex; + } + + /** + * Returns the next element in the array. + * + * @return the next element in the array + * @throws NoSuchElementException if all the elements in the array + * have already been returned + */ + @SuppressWarnings("unchecked") + public E next() { + if (hasNext() == false) { + throw new NoSuchElementException(); + } + return (E) Array.get(array, index++); + } + + /** + * Throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException always + */ + public void remove() { + throw new UnsupportedOperationException("remove() method is not supported"); + } + + // Properties + //----------------------------------------------------------------------- + /** + * Gets the array that this iterator is iterating over. + * + * @return the array this iterator iterates over. + */ + public Object getArray() { + return array; + } + + /** + * Gets the start index to loop from. + * + * @return the start index + * @since 4.0 + */ + public int getStartIndex() { + return this.startIndex; + } + + /** + * Gets the end index to loop to. + * + * @return the end index + * @since 4.0 + */ + public int getEndIndex() { + return this.endIndex; + } + + /** + * Resets the iterator back to the start index. + */ + public void reset() { + this.index = this.startIndex; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/ArrayListIterator.java b/src/org/apache/commons/collections4/iterators/ArrayListIterator.java new file mode 100644 index 0000000..4d363e4 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ArrayListIterator.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.lang.reflect.Array; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableListIterator; + +/** + * Implements a {@link ListIterator} over an array. + *

              + * The array can be either an array of object or of primitives. If you know + * that you have an object array, the {@link ObjectArrayListIterator} + * class is a better choice, as it will perform better. + * + *

              + * This iterator does not support {@link #add(Object)} or {@link #remove()}, as the array + * cannot be changed in size. The {@link #set(Object)} method is supported however. + * + * @see org.apache.commons.collections4.iterators.ArrayIterator + * @see java.util.Iterator + * @see java.util.ListIterator + * + * @since 3.0 + * @version $Id: ArrayListIterator.java 1543955 2013-11-20 21:23:53Z tn $ + */ +public class ArrayListIterator extends ArrayIterator + implements ResettableListIterator { + + /** + * Holds the index of the last item returned by a call to next() + * or previous(). This is set to -1 if neither method + * has yet been invoked. lastItemIndex is used to to implement + * the {@link #set} method. + */ + private int lastItemIndex = -1; + + // Constructors + // ---------------------------------------------------------------------- + /** + * Constructs an ArrayListIterator that will iterate over the values in the + * specified array. + * + * @param array the array to iterate over + * @throws IllegalArgumentException if array is not an array. + * @throws NullPointerException if array is null + */ + public ArrayListIterator(final Object array) { + super(array); + } + + /** + * Constructs an ArrayListIterator that will iterate over the values in the + * specified array from a specific start index. + * + * @param array the array to iterate over + * @param startIndex the index to start iterating at + * @throws IllegalArgumentException if array is not an array. + * @throws NullPointerException if array is null + * @throws IndexOutOfBoundsException if the start index is out of bounds + */ + public ArrayListIterator(final Object array, final int startIndex) { + super(array, startIndex); + } + + /** + * Construct an ArrayListIterator that will iterate over a range of values + * in the specified array. + * + * @param array the array to iterate over + * @param startIndex the index to start iterating at + * @param endIndex the index (exclusive) to finish iterating at + * @throws IllegalArgumentException if array is not an array. + * @throws IndexOutOfBoundsException if the start or end index is out of bounds + * @throws IllegalArgumentException if end index is before the start + * @throws NullPointerException if array is null + */ + public ArrayListIterator(final Object array, final int startIndex, final int endIndex) { + super(array, startIndex, endIndex); + } + + // ListIterator interface + //----------------------------------------------------------------------- + /** + * Returns true if there are previous elements to return from the array. + * + * @return true if there is a previous element to return + */ + public boolean hasPrevious() { + return this.index > this.startIndex; + } + + /** + * Gets the previous element from the array. + * + * @return the previous element + * @throws NoSuchElementException if there is no previous element + */ + @SuppressWarnings("unchecked") + public E previous() { + if (hasPrevious() == false) { + throw new NoSuchElementException(); + } + this.lastItemIndex = --this.index; + return (E) Array.get(this.array, this.index); + } + + /** + * Gets the next element from the array. + * + * @return the next element + * @throws NoSuchElementException if there is no next element + */ + @Override + @SuppressWarnings("unchecked") + public E next() { + if (hasNext() == false) { + throw new NoSuchElementException(); + } + this.lastItemIndex = this.index; + return (E) Array.get(this.array, this.index++); + } + + /** + * Gets the next index to be retrieved. + * + * @return the index of the item to be retrieved next + */ + public int nextIndex() { + return this.index - this.startIndex; + } + + /** + * Gets the index of the item to be retrieved if {@link #previous()} is called. + * + * @return the index of the item to be retrieved next + */ + public int previousIndex() { + return this.index - this.startIndex - 1; + } + + /** + * This iterator does not support modification of its backing collection, and so will + * always throw an {@link UnsupportedOperationException} when this method is invoked. + * + * @param o the element to add + * @throws UnsupportedOperationException always thrown. + * @see java.util.ListIterator#set + */ + public void add(final Object o) { + throw new UnsupportedOperationException("add() method is not supported"); + } + + /** + * Sets the element under the cursor. + *

              + * This method sets the element that was returned by the last call + * to {@link #next()} of {@link #previous()}. + *

              + * Note: {@link ListIterator} implementations that support + * add() and remove() only allow set() to be called + * once per call to next() or previous (see the {@link ListIterator} + * javadoc for more details). Since this implementation does + * not support add() or remove(), set() may be + * called as often as desired. + * + * @param o the element to set + * @throws IllegalStateException if {@link #next()} or {@link #previous()} has not been called + * before {@link #set(Object)} + * @see java.util.ListIterator#set + */ + public void set(final Object o) { + if (this.lastItemIndex == -1) { + throw new IllegalStateException("must call next() or previous() before a call to set()"); + } + + Array.set(this.array, this.lastItemIndex, o); + } + + /** + * Resets the iterator back to the start index. + */ + @Override + public void reset() { + super.reset(); + this.lastItemIndex = -1; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/BoundedIterator.java b/src/org/apache/commons/collections4/iterators/BoundedIterator.java new file mode 100644 index 0000000..16973bc --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/BoundedIterator.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Decorates another iterator to return elements in a specific range. + *

              + * The decorated iterator is bounded in the range [offset, offset+max). + * The {@code offset} corresponds to the position of the first element to + * be returned from the decorated iterator, and {@code max} is the maximum + * number of elements to be returned at most. + *

              + * In case an offset parameter other than 0 is provided, the decorated + * iterator is immediately advanced to this position, skipping all elements + * before that position. + * + * @since 4.1 + * @version $Id: BoundedIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class BoundedIterator implements Iterator { + + /** The iterator being decorated. */ + private final Iterator iterator; + + /** The offset to bound the first element return */ + private final long offset; + + /** The max number of elements to return */ + private final long max; + + /** The position of the current element */ + private long pos; + + //----------------------------------------------------------------------- + + /** + * Decorates the specified iterator to return at most the given number of elements, + * skipping all elements until the iterator reaches the position at {@code offset}. + *

              + * The iterator is immediately advanced until it reaches the position at {@code offset}, + * incurring O(n) time. + * + * @param iterator the iterator to be decorated + * @param offset the index of the first element of the decorated iterator to return + * @param max the maximum number of elements of the decorated iterator to return + * @throws NullPointerException if iterator is null + * @throws IllegalArgumentException if either offset or max is negative + */ + public BoundedIterator(final Iterator iterator, final long offset, final long max) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (offset < 0) { + throw new IllegalArgumentException("Offset parameter must not be negative."); + } + if (max < 0) { + throw new IllegalArgumentException("Max parameter must not be negative."); + } + + this.iterator = iterator; + this.offset = offset; + this.max = max; + pos = 0; + init(); + } + + /** + * Advances the underlying iterator to the beginning of the bounded range. + */ + private void init() { + while (pos < offset && iterator.hasNext()) { + iterator.next(); + pos++; + } + } + + //----------------------------------------------------------------------- + + public boolean hasNext() { + if (!checkBounds()) { + return false; + } + return iterator.hasNext(); + } + + /** + * Checks whether the iterator is still within its bounded range. + * @return {@code true} if the iterator is within its bounds, {@code false} otherwise + */ + private boolean checkBounds() { + if (pos - offset + 1 > max) { + return false; + } + return true; + } + + public E next() { + if (!checkBounds()) { + throw new NoSuchElementException(); + } + final E next = iterator.next(); + pos++; + return next; + } + + /** + * {@inheritDoc} + *

              + * In case an offset other than 0 was specified, the underlying iterator will be advanced + * to this position upon creation. A call to {@link #remove()} will still result in an + * {@link IllegalStateException} if no explicit call to {@link #next()} has been made prior + * to calling {@link #remove()}. + */ + public void remove() { + if (pos <= offset) { + throw new IllegalStateException("remove() can not be called before calling next()"); + } + iterator.remove(); + } +} diff --git a/src/org/apache/commons/collections4/iterators/CollatingIterator.java b/src/org/apache/commons/collections4/iterators/CollatingIterator.java new file mode 100644 index 0000000..e8649a4 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/CollatingIterator.java @@ -0,0 +1,397 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.list.UnmodifiableList; + + +/** + * Provides an ordered iteration over the elements contained in a collection of + * ordered Iterators. + *

              + * Given two ordered {@link Iterator} instances A and + * B, the {@link #next} method on this iterator will return the + * lesser of A.next() and B.next(). + * + * @since 2.1 + * @version $Id: CollatingIterator.java 1683632 2015-06-04 20:38:03Z tn $ + */ +public class CollatingIterator implements Iterator { + + /** The {@link Comparator} used to evaluate order. */ + private Comparator comparator = null; + + /** The list of {@link Iterator}s to evaluate. */ + private List> iterators = null; + + /** {@link Iterator#next Next} objects peeked from each iterator. */ + private List values = null; + + /** Whether or not each {@link #values} element has been set. */ + private BitSet valueSet = null; + + /** + * Index of the {@link #iterators iterator} from whom the last returned + * value was obtained. + */ + private int lastReturned = -1; + + // Constructors + // ---------------------------------------------------------------------- + /** + * Constructs a new CollatingIterator. A comparator must be + * set by calling {@link #setComparator(Comparator)} before invoking + * {@link #hasNext()}, or {@link #next()} for the first time. Child + * iterators will have to be manually added using the + * {@link #addIterator(Iterator)} method. + */ + public CollatingIterator() { + this(null, 2); + } + + /** + * Constructs a new CollatingIterator that will used the + * specified comparator for ordering. Child iterators will have to be + * manually added using the {@link #addIterator(Iterator)} method. + * + * @param comp the comparator to use to sort; must not be null, + * unless you'll be invoking {@link #setComparator(Comparator)} later on. + */ + public CollatingIterator(final Comparator comp) { + this(comp, 2); + } + + /** + * Constructs a new CollatingIterator that will used the + * specified comparator for ordering and have the specified initial + * capacity. Child iterators will have to be manually added using the + * {@link #addIterator(Iterator)} method. + * + * @param comp the comparator to use to sort; must not be null, + * unless you'll be invoking {@link #setComparator(Comparator)} later on. + * @param initIterCapacity the initial capacity for the internal list of + * child iterators + */ + public CollatingIterator(final Comparator comp, final int initIterCapacity) { + iterators = new ArrayList>(initIterCapacity); + setComparator(comp); + } + + /** + * Constructs a new CollatingIterator that will use the + * specified comparator to provide ordered iteration over the two given + * iterators. + * + * @param comp the comparator to use to sort; must not be null, + * unless you'll be invoking {@link #setComparator(Comparator)} later on. + * @param a the first child ordered iterator + * @param b the second child ordered iterator + * @throws NullPointerException if either iterator is null + */ + public CollatingIterator(final Comparator comp, final Iterator a, + final Iterator b) { + this(comp, 2); + addIterator(a); + addIterator(b); + } + + /** + * Constructs a new CollatingIterator that will use the + * specified comparator to provide ordered iteration over the array of + * iterators. + * + * @param comp the comparator to use to sort; must not be null, + * unless you'll be invoking {@link #setComparator(Comparator)} later on. + * @param iterators the array of iterators + * @throws NullPointerException if iterators array is or contains null + */ + public CollatingIterator(final Comparator comp, final Iterator[] iterators) { + this(comp, iterators.length); + for (final Iterator iterator : iterators) { + addIterator(iterator); + } + } + + /** + * Constructs a new CollatingIterator that will use the + * specified comparator to provide ordered iteration over the collection of + * iterators. + * + * @param comp the comparator to use to sort; must not be null, + * unless you'll be invoking {@link #setComparator(Comparator)} later on. + * @param iterators the collection of iterators + * @throws NullPointerException if the iterators collection is or contains null + * @throws ClassCastException if the iterators collection contains an + * element that's not an {@link Iterator} + */ + public CollatingIterator(final Comparator comp, final Collection> iterators) { + this(comp, iterators.size()); + for (final Iterator iterator : iterators) { + addIterator(iterator); + } + } + + // Public Methods + // ---------------------------------------------------------------------- + /** + * Adds the given {@link Iterator} to the iterators being collated. + * + * @param iterator the iterator to add to the collation, must not be null + * @throws IllegalStateException if iteration has started + * @throws NullPointerException if the iterator is null + */ + public void addIterator(final Iterator iterator) { + checkNotStarted(); + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + iterators.add(iterator); + } + + /** + * Sets the iterator at the given index. + * + * @param index index of the Iterator to replace + * @param iterator Iterator to place at the given index + * @throws IndexOutOfBoundsException if index < 0 or index > size() + * @throws IllegalStateException if iteration has started + * @throws NullPointerException if the iterator is null + */ + public void setIterator(final int index, final Iterator iterator) { + checkNotStarted(); + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + iterators.set(index, iterator); + } + + /** + * Gets the list of Iterators (unmodifiable). + * + * @return the unmodifiable list of iterators added + */ + public List> getIterators() { + return UnmodifiableList.unmodifiableList(iterators); + } + + /** + * Gets the {@link Comparator} by which collatation occurs. + * + * @return the {@link Comparator} + */ + public Comparator getComparator() { + return comparator; + } + + /** + * Sets the {@link Comparator} by which collation occurs. If you + * would like to use the natural sort order (or, in other words, + * if the elements in the iterators are implementing the + * {@link java.lang.Comparable} interface), then use the + * {@link org.apache.commons.collections4.comparators.ComparableComparator}. + * + * @param comp the {@link Comparator} to set + * @throws IllegalStateException if iteration has started + */ + public void setComparator(final Comparator comp) { + checkNotStarted(); + comparator = comp; + } + + // Iterator Methods + // ------------------------------------------------------------------- + /** + * Returns true if any child iterator has remaining elements. + * + * @return true if this iterator has remaining elements + */ + public boolean hasNext() { + start(); + return anyValueSet(valueSet) || anyHasNext(iterators); + } + + /** + * Returns the next ordered element from a child iterator. + * + * @return the next ordered element + * @throws NoSuchElementException if no child iterator has any more elements + */ + public E next() throws NoSuchElementException { + if (hasNext() == false) { + throw new NoSuchElementException(); + } + final int leastIndex = least(); + if (leastIndex == -1) { + throw new NoSuchElementException(); + } + final E val = values.get(leastIndex); + clear(leastIndex); + lastReturned = leastIndex; + return val; + } + + /** + * Removes the last returned element from the child iterator that produced it. + * + * @throws IllegalStateException if there is no last returned element, or if + * the last returned element has already been removed + */ + public void remove() { + if (lastReturned == -1) { + throw new IllegalStateException("No value can be removed at present"); + } + iterators.get(lastReturned).remove(); + } + + /** + * Returns the index of the iterator that returned the last element. + * + * @return the index of the iterator that returned the last element + * @throws IllegalStateException if there is no last returned element + */ + public int getIteratorIndex() { + if (lastReturned == -1) { + throw new IllegalStateException("No value has been returned yet"); + } + + return lastReturned; + } + + // Private Methods + // ------------------------------------------------------------------- + /** + * Initializes the collating state if it hasn't been already. + */ + private void start() { + if (values == null) { + values = new ArrayList(iterators.size()); + valueSet = new BitSet(iterators.size()); + for (int i = 0; i < iterators.size(); i++) { + values.add(null); + valueSet.clear(i); + } + } + } + + /** + * Sets the {@link #values} and {@link #valueSet} attributes at position + * i to the next value of the {@link #iterators iterator} at position + * i, or clear them if the ith iterator has no next + * value. + * + * @return {@code false} iff there was no value to set + */ + private boolean set(final int i) { + final Iterator it = iterators.get(i); + if (it.hasNext()) { + values.set(i, it.next()); + valueSet.set(i); + return true; + } + values.set(i, null); + valueSet.clear(i); + return false; + } + + /** + * Clears the {@link #values} and {@link #valueSet} attributes at position + * i. + */ + private void clear(final int i) { + values.set(i, null); + valueSet.clear(i); + } + + /** + * Throws {@link IllegalStateException} if iteration has started via + * {@link #start}. + * + * @throws IllegalStateException if iteration started + */ + private void checkNotStarted() throws IllegalStateException { + if (values != null) { + throw new IllegalStateException("Can't do that after next or hasNext has been called."); + } + } + + /** + * Returns the index of the least element in {@link #values}, + * {@link #set(int) setting} any uninitialized values. + * + * @throws NullPointerException if no comparator is set + */ + private int least() { + int leastIndex = -1; + E leastObject = null; + for (int i = 0; i < values.size(); i++) { + if (valueSet.get(i) == false) { + set(i); + } + if (valueSet.get(i)) { + if (leastIndex == -1) { + leastIndex = i; + leastObject = values.get(i); + } else { + final E curObject = values.get(i); + if (comparator == null) { + throw new NullPointerException("You must invoke setComparator() to set a comparator first."); + } + if (comparator.compare(curObject, leastObject) < 0) { + leastObject = curObject; + leastIndex = i; + } + } + } + } + return leastIndex; + } + + /** + * Returns true iff any bit in the given set is + * true. + */ + private boolean anyValueSet(final BitSet set) { + for (int i = 0; i < set.size(); i++) { + if (set.get(i)) { + return true; + } + } + return false; + } + + /** + * Returns true iff any {@link Iterator} in the given list has + * a next value. + */ + private boolean anyHasNext(final List> iters) { + for (final Iterator iterator : iters) { + if (iterator.hasNext()) { + return true; + } + } + return false; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/EmptyIterator.java b/src/org/apache/commons/collections4/iterators/EmptyIterator.java new file mode 100644 index 0000000..8e19bb5 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/EmptyIterator.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +import org.apache.commons.collections4.ResettableIterator; + +/** + * Provides an implementation of an empty iterator. + *

              + * This class provides an implementation of an empty iterator. + * This class provides for binary compatibility between Commons Collections + * 2.1.1 and 3.1 due to issues with IteratorUtils. + * + * @since 2.1.1 and 3.1 + * @version $Id: EmptyIterator.java 1543955 2013-11-20 21:23:53Z tn $ + */ +public class EmptyIterator extends AbstractEmptyIterator implements ResettableIterator { + + /** + * Singleton instance of the iterator. + * @since 3.1 + */ + @SuppressWarnings("rawtypes") + public static final ResettableIterator RESETTABLE_INSTANCE = new EmptyIterator(); + + /** + * Singleton instance of the iterator. + * @since 2.1.1 and 3.1 + */ + @SuppressWarnings("rawtypes") + public static final Iterator INSTANCE = RESETTABLE_INSTANCE; + + /** + * Get a typed resettable empty iterator instance. + * @param the element type + * @return ResettableIterator + */ + @SuppressWarnings("unchecked") + public static ResettableIterator resettableEmptyIterator() { + return (ResettableIterator) RESETTABLE_INSTANCE; + } + + /** + * Get a typed empty iterator instance. + * @param the element type + * @return Iterator + */ + @SuppressWarnings("unchecked") + public static Iterator emptyIterator() { + return (Iterator) INSTANCE; + } + + /** + * Constructor. + */ + protected EmptyIterator() { + super(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/EmptyListIterator.java b/src/org/apache/commons/collections4/iterators/EmptyListIterator.java new file mode 100644 index 0000000..c0e9619 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/EmptyListIterator.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ListIterator; + +import org.apache.commons.collections4.ResettableListIterator; + +/** + * Provides an implementation of an empty list iterator. + *

              + * This class provides an implementation of an empty list iterator. This class + * provides for binary compatibility between Commons Collections 2.1.1 and 3.1 + * due to issues with IteratorUtils. + * + * @since 2.1.1 and 3.1 + * @version $Id: EmptyListIterator.java 1543955 2013-11-20 21:23:53Z tn $ + */ +public class EmptyListIterator extends AbstractEmptyIterator implements + ResettableListIterator { + + /** + * Singleton instance of the iterator. + * @since 3.1 + */ + @SuppressWarnings("rawtypes") + public static final ResettableListIterator RESETTABLE_INSTANCE = new EmptyListIterator(); + + /** + * Singleton instance of the iterator. + * @since 2.1.1 and 3.1 + */ + @SuppressWarnings("rawtypes") + public static final ListIterator INSTANCE = RESETTABLE_INSTANCE; + + /** + * Get a typed instance of the iterator. + * @param the element type + * @return {@link ResettableListIterator} + */ + @SuppressWarnings("unchecked") + public static ResettableListIterator resettableEmptyListIterator() { + return (ResettableListIterator) RESETTABLE_INSTANCE; + } + + /** + * Get a typed instance of the iterator. + * @param the element type + * @return {@link ListIterator} + */ + @SuppressWarnings("unchecked") + public static ListIterator emptyListIterator() { + return (ListIterator) INSTANCE; + } + + /** + * Constructor. + */ + protected EmptyListIterator() { + super(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/EmptyMapIterator.java b/src/org/apache/commons/collections4/iterators/EmptyMapIterator.java new file mode 100644 index 0000000..6ec8ed8 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/EmptyMapIterator.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.ResettableIterator; + +/** + * Provides an implementation of an empty map iterator. + * + * @since 3.1 + * @version $Id: EmptyMapIterator.java 1543955 2013-11-20 21:23:53Z tn $ + */ +public class EmptyMapIterator extends AbstractEmptyMapIterator implements + MapIterator, ResettableIterator { + + /** + * Singleton instance of the iterator. + * @since 3.1 + */ + @SuppressWarnings("rawtypes") + public static final MapIterator INSTANCE = new EmptyMapIterator(); + + /** + * Get a typed instance of the iterator. + * @param the key type + * @param the value type + * @return {@link MapIterator} + */ + @SuppressWarnings("unchecked") + public static MapIterator emptyMapIterator() { + return (MapIterator) INSTANCE; + } + + /** + * Constructor. + */ + protected EmptyMapIterator() { + super(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/EmptyOrderedIterator.java b/src/org/apache/commons/collections4/iterators/EmptyOrderedIterator.java new file mode 100644 index 0000000..8fbcca2 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/EmptyOrderedIterator.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import org.apache.commons.collections4.OrderedIterator; +import org.apache.commons.collections4.ResettableIterator; + +/** + * Provides an implementation of an empty ordered iterator. + * + * @since 3.1 + * @version $Id: EmptyOrderedIterator.java 1543955 2013-11-20 21:23:53Z tn $ + */ +public class EmptyOrderedIterator extends AbstractEmptyIterator + implements OrderedIterator, ResettableIterator { + + /** + * Singleton instance of the iterator. + * @since 3.1 + */ + @SuppressWarnings("rawtypes") + public static final OrderedIterator INSTANCE = new EmptyOrderedIterator(); + + /** + * Typed instance of the iterator. + * @param the element type + * @return OrderedIterator + */ + @SuppressWarnings("unchecked") + public static OrderedIterator emptyOrderedIterator() { + return (OrderedIterator) INSTANCE; + } + + /** + * Constructor. + */ + protected EmptyOrderedIterator() { + super(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/EmptyOrderedMapIterator.java b/src/org/apache/commons/collections4/iterators/EmptyOrderedMapIterator.java new file mode 100644 index 0000000..614e602 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/EmptyOrderedMapIterator.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.ResettableIterator; + +/** + * Provides an implementation of an empty ordered map iterator. + * + * @since 3.1 + * @version $Id: EmptyOrderedMapIterator.java 1543955 2013-11-20 21:23:53Z tn $ + */ +public class EmptyOrderedMapIterator extends AbstractEmptyMapIterator + implements OrderedMapIterator, ResettableIterator { + + /** + * Singleton instance of the iterator. + * @since 3.1 + */ + @SuppressWarnings("rawtypes") + public static final OrderedMapIterator INSTANCE = new EmptyOrderedMapIterator(); + + /** + * Get a typed instance of the iterator. + * @param the key type + * @param the value type + * @return {@link OrderedMapIterator} + */ + @SuppressWarnings("unchecked") + public static OrderedMapIterator emptyOrderedMapIterator() { + return (OrderedMapIterator) INSTANCE; + } + + /** + * Constructor. + */ + protected EmptyOrderedMapIterator() { + super(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/EntrySetMapIterator.java b/src/org/apache/commons/collections4/iterators/EntrySetMapIterator.java new file mode 100644 index 0000000..bb9cdc8 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/EntrySetMapIterator.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.ResettableIterator; + +/** + * Implements a MapIterator using a Map entrySet. + * Reverse iteration is not supported. + *
              + * MapIterator it = map.mapIterator();
              + * while (it.hasNext()) {
              + *   Object key = it.next();
              + *   Object value = it.getValue();
              + *   it.setValue(newValue);
              + * }
              + * 
              + * + * @since 3.0 + * @version $Id: EntrySetMapIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public class EntrySetMapIterator implements MapIterator, ResettableIterator { + + private final Map map; + private Iterator> iterator; + private Map.Entry last; + private boolean canRemove = false; + + /** + * Constructor. + * + * @param map the map to iterate over + */ + public EntrySetMapIterator(final Map map) { + super(); + this.map = map; + this.iterator = map.entrySet().iterator(); + } + + //----------------------------------------------------------------------- + /** + * Checks to see if there are more entries still to be iterated. + * + * @return true if the iterator has more elements + */ + public boolean hasNext() { + return iterator.hasNext(); + } + + /** + * Gets the next key from the Map. + * + * @return the next key in the iteration + * @throws java.util.NoSuchElementException if the iteration is finished + */ + public K next() { + last = iterator.next(); + canRemove = true; + return last.getKey(); + } + + //----------------------------------------------------------------------- + /** + * Removes the last returned key from the underlying Map. + *

              + * This method can be called once per call to next(). + * + * @throws UnsupportedOperationException if remove is not supported by the map + * @throws IllegalStateException if next() has not yet been called + * @throws IllegalStateException if remove() has already been called + * since the last call to next() + */ + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + iterator.remove(); + last = null; + canRemove = false; + } + + //----------------------------------------------------------------------- + /** + * Gets the current key, which is the key returned by the last call + * to next(). + * + * @return the current key + * @throws IllegalStateException if next() has not yet been called + */ + public K getKey() { + if (last == null) { + throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()"); + } + return last.getKey(); + } + + /** + * Gets the current value, which is the value associated with the last key + * returned by next(). + * + * @return the current value + * @throws IllegalStateException if next() has not yet been called + */ + public V getValue() { + if (last == null) { + throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()"); + } + return last.getValue(); + } + + /** + * Sets the value associated with the current key. + * + * @param value the new value + * @return the previous value + * @throws UnsupportedOperationException if setValue is not supported by the map + * @throws IllegalStateException if next() has not yet been called + * @throws IllegalStateException if remove() has been called since the + * last call to next() + */ + public V setValue(final V value) { + if (last == null) { + throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()"); + } + return last.setValue(value); + } + + //----------------------------------------------------------------------- + /** + * Resets the state of the iterator. + */ + public void reset() { + iterator = map.entrySet().iterator(); + last = null; + canRemove = false; + } + + /** + * Gets the iterator as a String. + * + * @return a string version of the iterator + */ + @Override + public String toString() { + if (last != null) { + return "MapIterator[" + getKey() + "=" + getValue() + "]"; + } + return "MapIterator[]"; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/EnumerationIterator.java b/src/org/apache/commons/collections4/iterators/EnumerationIterator.java new file mode 100644 index 0000000..8675de9 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/EnumerationIterator.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; + +/** + * Adapter to make {@link Enumeration Enumeration} instances appear + * to be {@link Iterator Iterator} instances. + * + * @since 1.0 + * @version $Id: EnumerationIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public class EnumerationIterator implements Iterator { + + /** The collection to remove elements from */ + private final Collection collection; + /** The enumeration being converted */ + private Enumeration enumeration; + /** The last object retrieved */ + private E last; + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructs a new EnumerationIterator that will not + * function until {@link #setEnumeration(Enumeration)} is called. + */ + public EnumerationIterator() { + this(null, null); + } + + /** + * Constructs a new EnumerationIterator that provides + * an iterator view of the given enumeration. + * + * @param enumeration the enumeration to use + */ + public EnumerationIterator(final Enumeration enumeration) { + this(enumeration, null); + } + + /** + * Constructs a new EnumerationIterator that will remove + * elements from the specified collection. + * + * @param enumeration the enumeration to use + * @param collection the collection to remove elements from + */ + public EnumerationIterator(final Enumeration enumeration, final Collection collection) { + super(); + this.enumeration = enumeration; + this.collection = collection; + this.last = null; + } + + // Iterator interface + //----------------------------------------------------------------------- + /** + * Returns true if the underlying enumeration has more elements. + * + * @return true if the underlying enumeration has more elements + * @throws NullPointerException if the underlying enumeration is null + */ + public boolean hasNext() { + return enumeration.hasMoreElements(); + } + + /** + * Returns the next object from the enumeration. + * + * @return the next object from the enumeration + * @throws NullPointerException if the enumeration is null + */ + public E next() { + last = enumeration.nextElement(); + return last; + } + + /** + * Removes the last retrieved element if a collection is attached. + *

              + * Functions if an associated Collection is known. + * If so, the first occurrence of the last returned object from this + * iterator will be removed from the collection. + * + * @exception IllegalStateException next() not called. + * @exception UnsupportedOperationException if no associated collection + */ + public void remove() { + if (collection != null) { + if (last != null) { + collection.remove(last); + } else { + throw new IllegalStateException("next() must have been called for remove() to function"); + } + } else { + throw new UnsupportedOperationException("No Collection associated with this Iterator"); + } + } + + // Properties + //----------------------------------------------------------------------- + /** + * Returns the underlying enumeration. + * + * @return the underlying enumeration + */ + public Enumeration getEnumeration() { + return enumeration; + } + + /** + * Sets the underlying enumeration. + * + * @param enumeration the new underlying enumeration + */ + public void setEnumeration(final Enumeration enumeration) { + this.enumeration = enumeration; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/FilterIterator.java b/src/org/apache/commons/collections4/iterators/FilterIterator.java new file mode 100644 index 0000000..a58f4ac --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/FilterIterator.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.Predicate; + +/** + * Decorates another {@link Iterator} using a predicate to filter elements. + *

              + * This iterator decorates the underlying iterator, only allowing through + * those elements that match the specified {@link Predicate Predicate}. + * + * @since 1.0 + * @version $Id: FilterIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public class FilterIterator implements Iterator { + + /** The iterator being used */ + private Iterator iterator; + /** The predicate being used */ + private Predicate predicate; + /** The next object in the iteration */ + private E nextObject; + /** Whether the next object has been calculated yet */ + private boolean nextObjectSet = false; + + //----------------------------------------------------------------------- + /** + * Constructs a new FilterIterator that will not function + * until {@link #setIterator(Iterator) setIterator} is invoked. + */ + public FilterIterator() { + super(); + } + + /** + * Constructs a new FilterIterator that will not function + * until {@link #setPredicate(Predicate) setPredicate} is invoked. + * + * @param iterator the iterator to use + */ + public FilterIterator(final Iterator iterator) { + super(); + this.iterator = iterator; + } + + /** + * Constructs a new FilterIterator that will use the + * given iterator and predicate. + * + * @param iterator the iterator to use + * @param predicate the predicate to use + */ + public FilterIterator(final Iterator iterator, final Predicate predicate) { + super(); + this.iterator = iterator; + this.predicate = predicate; + } + + //----------------------------------------------------------------------- + /** + * Returns true if the underlying iterator contains an object that + * matches the predicate. + * + * @return true if there is another object that matches the predicate + * @throws NullPointerException if either the iterator or predicate are null + */ + public boolean hasNext() { + return nextObjectSet || setNextObject(); + } + + /** + * Returns the next object that matches the predicate. + * + * @return the next object which matches the given predicate + * @throws NullPointerException if either the iterator or predicate are null + * @throws NoSuchElementException if there are no more elements that + * match the predicate + */ + public E next() { + if (!nextObjectSet) { + if (!setNextObject()) { + throw new NoSuchElementException(); + } + } + nextObjectSet = false; + return nextObject; + } + + /** + * Removes from the underlying collection of the base iterator the last + * element returned by this iterator. + * This method can only be called + * if next() was called, but not after + * hasNext(), because the hasNext() call + * changes the base iterator. + * + * @throws IllegalStateException if hasNext() has already + * been called. + */ + public void remove() { + if (nextObjectSet) { + throw new IllegalStateException("remove() cannot be called"); + } + iterator.remove(); + } + + //----------------------------------------------------------------------- + /** + * Gets the iterator this iterator is using. + * + * @return the iterator + */ + public Iterator getIterator() { + return iterator; + } + + /** + * Sets the iterator for this iterator to use. + * If iteration has started, this effectively resets the iterator. + * + * @param iterator the iterator to use + */ + public void setIterator(final Iterator iterator) { + this.iterator = iterator; + nextObject = null; + nextObjectSet = false; + } + + //----------------------------------------------------------------------- + /** + * Gets the predicate this iterator is using. + * + * @return the predicate + */ + public Predicate getPredicate() { + return predicate; + } + + /** + * Sets the predicate this the iterator to use. + * + * @param predicate the predicate to use + */ + public void setPredicate(final Predicate predicate) { + this.predicate = predicate; + nextObject = null; + nextObjectSet = false; + } + + //----------------------------------------------------------------------- + /** + * Set nextObject to the next object. If there are no more + * objects then return false. Otherwise, return true. + */ + private boolean setNextObject() { + while (iterator.hasNext()) { + final E object = iterator.next(); + if (predicate.evaluate(object)) { + nextObject = object; + nextObjectSet = true; + return true; + } + } + return false; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/FilterListIterator.java b/src/org/apache/commons/collections4/iterators/FilterListIterator.java new file mode 100644 index 0000000..ffa2513 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/FilterListIterator.java @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.Predicate; + +/** + * Decorates another {@link ListIterator} using a predicate to filter elements. + *

              + * This iterator decorates the underlying iterator, only allowing through + * those elements that match the specified {@link Predicate Predicate}. + * + * @since 2.0 + * @version $Id: FilterListIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public class FilterListIterator implements ListIterator { + + /** The iterator being used */ + private ListIterator iterator; + + /** The predicate being used */ + private Predicate predicate; + + /** + * The value of the next (matching) object, when + * {@link #nextObjectSet} is true. + */ + private E nextObject; + + /** + * Whether or not the {@link #nextObject} has been set + * (possibly to null). + */ + private boolean nextObjectSet = false; + + /** + * The value of the previous (matching) object, when + * {@link #previousObjectSet} is true. + */ + private E previousObject; + + /** + * Whether or not the {@link #previousObject} has been set + * (possibly to null). + */ + private boolean previousObjectSet = false; + + /** + * The index of the element that would be returned by {@link #next}. + */ + private int nextIndex = 0; + + //----------------------------------------------------------------------- + /** + * Constructs a new FilterListIterator that will not function + * until {@link #setListIterator(ListIterator) setListIterator} + * and {@link #setPredicate(Predicate) setPredicate} are invoked. + */ + public FilterListIterator() { + super(); + } + + /** + * Constructs a new FilterListIterator that will not + * function until {@link #setPredicate(Predicate) setPredicate} is invoked. + * + * @param iterator the iterator to use + */ + public FilterListIterator(final ListIterator iterator ) { + super(); + this.iterator = iterator; + } + + /** + * Constructs a new FilterListIterator. + * + * @param iterator the iterator to use + * @param predicate the predicate to use + */ + public FilterListIterator(final ListIterator iterator, final Predicate predicate) { + super(); + this.iterator = iterator; + this.predicate = predicate; + } + + /** + * Constructs a new FilterListIterator that will not function + * until {@link #setListIterator(ListIterator) setListIterator} is invoked. + * + * @param predicate the predicate to use. + */ + public FilterListIterator(final Predicate predicate) { + super(); + this.predicate = predicate; + } + + //----------------------------------------------------------------------- + /** Not supported. */ + public void add(final E o) { + throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported."); + } + + public boolean hasNext() { + return nextObjectSet || setNextObject(); + } + + public boolean hasPrevious() { + return previousObjectSet || setPreviousObject(); + } + + public E next() { + if (!nextObjectSet) { + if (!setNextObject()) { + throw new NoSuchElementException(); + } + } + nextIndex++; + final E temp = nextObject; + clearNextObject(); + return temp; + } + + public int nextIndex() { + return nextIndex; + } + + public E previous() { + if (!previousObjectSet) { + if (!setPreviousObject()) { + throw new NoSuchElementException(); + } + } + nextIndex--; + final E temp = previousObject; + clearPreviousObject(); + return temp; + } + + public int previousIndex() { + return nextIndex-1; + } + + /** Not supported. */ + public void remove() { + throw new UnsupportedOperationException("FilterListIterator.remove() is not supported."); + } + + /** Not supported. */ + public void set(final E o) { + throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported."); + } + + //----------------------------------------------------------------------- + /** + * Gets the iterator this iterator is using. + * + * @return the iterator. + */ + public ListIterator getListIterator() { + return iterator; + } + + /** + * Sets the iterator for this iterator to use. + * If iteration has started, this effectively resets the iterator. + * + * @param iterator the iterator to use + */ + public void setListIterator(final ListIterator iterator) { + this.iterator = iterator; + } + + //----------------------------------------------------------------------- + /** + * Gets the predicate this iterator is using. + * + * @return the predicate. + */ + public Predicate getPredicate() { + return predicate; + } + + /** + * Sets the predicate this the iterator to use. + * + * @param predicate the transformer to use + */ + public void setPredicate(final Predicate predicate) { + this.predicate = predicate; + } + + //----------------------------------------------------------------------- + private void clearNextObject() { + nextObject = null; + nextObjectSet = false; + } + + private boolean setNextObject() { + // if previousObjectSet, + // then we've walked back one step in the + // underlying list (due to a hasPrevious() call) + // so skip ahead one matching object + if (previousObjectSet) { + clearPreviousObject(); + if (!setNextObject()) { + return false; + } + clearNextObject(); + } + + if (iterator == null) { + return false; + } + while (iterator.hasNext()) { + final E object = iterator.next(); + if (predicate.evaluate(object)) { + nextObject = object; + nextObjectSet = true; + return true; + } + } + return false; + } + + private void clearPreviousObject() { + previousObject = null; + previousObjectSet = false; + } + + private boolean setPreviousObject() { + // if nextObjectSet, + // then we've walked back one step in the + // underlying list (due to a hasNext() call) + // so skip ahead one matching object + if (nextObjectSet) { + clearNextObject(); + if (!setPreviousObject()) { + return false; + } + clearPreviousObject(); + } + + if (iterator == null) { + return false; + } + while (iterator.hasPrevious()) { + final E object = iterator.previous(); + if (predicate.evaluate(object)) { + previousObject = object; + previousObjectSet = true; + return true; + } + } + return false; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/IteratorChain.java b/src/org/apache/commons/collections4/iterators/IteratorChain.java new file mode 100644 index 0000000..f6f7031 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/IteratorChain.java @@ -0,0 +1,279 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Queue; + +/** + * An IteratorChain is an Iterator that wraps a number of Iterators. + *

              + * This class makes multiple iterators look like one to the caller. When any + * method from the Iterator interface is called, the IteratorChain will delegate + * to a single underlying Iterator. The IteratorChain will invoke the Iterators + * in sequence until all Iterators are exhausted. + *

              + * Under many circumstances, linking Iterators together in this manner is more + * efficient (and convenient) than reading out the contents of each Iterator + * into a List and creating a new Iterator. + *

              + * Calling a method that adds new Iterator after a method in the Iterator + * interface has been called will result in an UnsupportedOperationException. + *

              + * NOTE: As from version 3.0, the IteratorChain may contain no iterators. In + * this case the class will function as an empty iterator. + *

              + * NOTE: As from version 4.0, the IteratorChain stores the iterators in a queue + * and removes any reference to them as soon as they are not used anymore. Thus + * the methods {@code setIterator(Iterator)} and {@code getIterators()} have been + * removed and {@link #size()} will return the number of remaining iterators in + * the queue. + * + * @since 2.1 + * @version $Id: IteratorChain.java 1482514 2013-05-14 18:36:12Z tn $ + */ +public class IteratorChain implements Iterator { + + /** The chain of iterators */ + private final Queue> iteratorChain = new LinkedList>(); + + /** The current iterator */ + private Iterator currentIterator = null; + + /** + * The "last used" Iterator is the Iterator upon which next() or hasNext() + * was most recently called used for the remove() operation only + */ + private Iterator lastUsedIterator = null; + + /** + * ComparatorChain is "locked" after the first time compare(Object,Object) + * is called + */ + private boolean isLocked = false; + + //----------------------------------------------------------------------- + /** + * Construct an IteratorChain with no Iterators. + *

              + * You will normally use {@link #addIterator(Iterator)} to add some + * iterators after using this constructor. + */ + public IteratorChain() { + super(); + } + + /** + * Construct an IteratorChain with a single Iterator. + *

              + * This method takes one iterator. The newly constructed iterator will + * iterate through that iterator. Thus calling this constructor on its own + * will have no effect other than decorating the input iterator. + *

              + * You will normally use {@link #addIterator(Iterator)} to add some more + * iterators after using this constructor. + * + * @param iterator the first child iterator in the IteratorChain, not null + * @throws NullPointerException if the iterator is null + */ + public IteratorChain(final Iterator iterator) { + super(); + addIterator(iterator); + } + + /** + * Constructs a new IteratorChain over the two given iterators. + *

              + * This method takes two iterators. The newly constructed iterator will + * iterate through each one of the input iterators in turn. + * + * @param first the first child iterator in the IteratorChain, not null + * @param second the second child iterator in the IteratorChain, not null + * @throws NullPointerException if either iterator is null + */ + public IteratorChain(final Iterator first, final Iterator second) { + super(); + addIterator(first); + addIterator(second); + } + + /** + * Constructs a new IteratorChain over the array of iterators. + *

              + * This method takes an array of iterators. The newly constructed iterator + * will iterate through each one of the input iterators in turn. + * + * @param iteratorChain the array of iterators, not null + * @throws NullPointerException if iterators array is or contains null + */ + @SafeVarargs + public IteratorChain(final Iterator... iteratorChain) { + super(); + for (final Iterator element : iteratorChain) { + addIterator(element); + } + } + + /** + * Constructs a new IteratorChain over the collection of + * iterators. + *

              + * This method takes a collection of iterators. The newly constructed + * iterator will iterate through each one of the input iterators in turn. + * + * @param iteratorChain the collection of iterators, not null + * @throws NullPointerException if iterators collection is or contains null + * @throws ClassCastException if iterators collection doesn't contain an + * iterator + */ + public IteratorChain(final Collection> iteratorChain) { + super(); + for (final Iterator iterator : iteratorChain) { + addIterator(iterator); + } + } + + //----------------------------------------------------------------------- + /** + * Add an Iterator to the end of the chain + * + * @param iterator Iterator to add + * @throws IllegalStateException if I've already started iterating + * @throws NullPointerException if the iterator is null + */ + public void addIterator(final Iterator iterator) { + checkLocked(); + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + iteratorChain.add(iterator); + } + + /** + * Returns the remaining number of Iterators in the current IteratorChain. + * + * @return Iterator count + */ + public int size() { + return iteratorChain.size(); + } + + /** + * Determine if modifications can still be made to the IteratorChain. + * IteratorChains cannot be modified once they have executed a method from + * the Iterator interface. + * + * @return true if IteratorChain cannot be modified, false if it can + */ + public boolean isLocked() { + return isLocked; + } + + /** + * Checks whether the iterator chain is now locked and in use. + */ + private void checkLocked() { + if (isLocked == true) { + throw new UnsupportedOperationException( + "IteratorChain cannot be changed after the first use of a method from the Iterator interface"); + } + } + + /** + * Lock the chain so no more iterators can be added. This must be called + * from all Iterator interface methods. + */ + private void lockChain() { + if (isLocked == false) { + isLocked = true; + } + } + + /** + * Updates the current iterator field to ensure that the current Iterator is + * not exhausted + */ + protected void updateCurrentIterator() { + if (currentIterator == null) { + if (iteratorChain.isEmpty()) { + currentIterator = EmptyIterator. emptyIterator(); + } else { + currentIterator = iteratorChain.remove(); + } + // set last used iterator here, in case the user calls remove + // before calling hasNext() or next() (although they shouldn't) + lastUsedIterator = currentIterator; + } + + while (currentIterator.hasNext() == false && !iteratorChain.isEmpty()) { + currentIterator = iteratorChain.remove(); + } + } + + //----------------------------------------------------------------------- + /** + * Return true if any Iterator in the IteratorChain has a remaining element. + * + * @return true if elements remain + */ + public boolean hasNext() { + lockChain(); + updateCurrentIterator(); + lastUsedIterator = currentIterator; + + return currentIterator.hasNext(); + } + + /** + * Returns the next Object of the current Iterator + * + * @return Object from the current Iterator + * @throws java.util.NoSuchElementException if all the Iterators are + * exhausted + */ + public E next() { + lockChain(); + updateCurrentIterator(); + lastUsedIterator = currentIterator; + + return currentIterator.next(); + } + + /** + * Removes from the underlying collection the last element returned by the + * Iterator. As with next() and hasNext(), this method calls remove() on the + * underlying Iterator. Therefore, this method may throw an + * UnsupportedOperationException if the underlying Iterator does not support + * this method. + * + * @throws UnsupportedOperationException if the remove operator is not + * supported by the underlying Iterator + * @throws IllegalStateException if the next method has not yet been called, + * or the remove method has already been called after the last call to the + * next method. + */ + public void remove() { + lockChain(); + if (currentIterator == null) { + updateCurrentIterator(); + } + lastUsedIterator.remove(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/IteratorEnumeration.java b/src/org/apache/commons/collections4/iterators/IteratorEnumeration.java new file mode 100644 index 0000000..3549918 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/IteratorEnumeration.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Enumeration; +import java.util.Iterator; + +/** + * Adapter to make an {@link Iterator Iterator} instance appear to be an + * {@link Enumeration Enumeration} instance. + * + * @since 1.0 + * @version $Id: IteratorEnumeration.java 1543728 2013-11-20 07:51:32Z ebourg $ + */ +public class IteratorEnumeration implements Enumeration { + + /** The iterator being decorated. */ + private Iterator iterator; + + /** + * Constructs a new IteratorEnumeration that will not function + * until {@link #setIterator(Iterator) setIterator} is invoked. + */ + public IteratorEnumeration() { + } + + /** + * Constructs a new IteratorEnumeration that will use the given + * iterator. + * + * @param iterator the iterator to use + */ + public IteratorEnumeration(final Iterator iterator) { + this.iterator = iterator; + } + + // Iterator interface + //------------------------------------------------------------------------- + + /** + * Returns true if the underlying iterator has more elements. + * + * @return true if the underlying iterator has more elements + */ + public boolean hasMoreElements() { + return iterator.hasNext(); + } + + /** + * Returns the next element from the underlying iterator. + * + * @return the next element from the underlying iterator. + * @throws java.util.NoSuchElementException if the underlying iterator has + * no more elements + */ + public E nextElement() { + return iterator.next(); + } + + // Properties + //------------------------------------------------------------------------- + + /** + * Returns the underlying iterator. + * + * @return the underlying iterator + */ + public Iterator getIterator() { + return iterator; + } + + /** + * Sets the underlying iterator. + * + * @param iterator the new underlying iterator + */ + public void setIterator(final Iterator iterator) { + this.iterator = iterator; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/IteratorIterable.java b/src/org/apache/commons/collections4/iterators/IteratorIterable.java new file mode 100644 index 0000000..4b7bb3c --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/IteratorIterable.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +import org.apache.commons.collections4.ResettableIterator; + +/** + * Adapter to make an {@link Iterator Iterator} instance appear to be an + * {@link Iterable Iterable} instance. The iterable can be constructed in one + * of two variants: single use, multiple use. + * + *

              + * In the single use iterable case, the iterable is only usable for one + * iterative operation over the source iterator. Subsequent iterative + * operations use the same, exhausted source iterator. To create a single use + * iterable, construct a new {@link IteratorIterable} using a {@link Iterator} + * that is NOT a {@link ResettableIterator} iterator: + *

              + *   Iterator iterator = // some non-resettable iterator
              + *   Iterable iterable = new IteratorIterable(iterator);
              + * 
              + *

              + * + *

              + * In the multiple use iterable case, the iterable is usable for any number of + * iterative operations over the source iterator. Of special note, even though + * the iterable supports multiple iterations, it does not support concurrent + * iterations. To implicitly create a multiple use iterable, construct a new + * {@link IteratorIterable} using a {@link ResettableIterator} iterator: + *

              + *   Integer[] array = {Integer.valueOf(1),Integer.valueOf(2),Integer.valueOf(3)};
              + *   Iterator iterator = IteratorUtils.arrayIterator(array); // a resettable iterator
              + *   Iterable iterable = new IteratorIterable(iterator);
              + * 
              + *

              + * + *

              + * A multiple use iterable can also be explicitly constructed using any + * {@link Iterator} and specifying true for the + * multipleUse flag: + *

              + *   Iterator iterator = // some non-resettable iterator
              + *   Iterable iterable = new IteratorIterable(iterator, true);
              + * 
              + *

              + * + * @since 4.0 + * @version $Id: IteratorIterable.java 1684123 2015-06-08 08:53:26Z tn $ + */ +public class IteratorIterable implements Iterable { + + /** + * Factory method to create an {@link Iterator Iterator} from another + * iterator over objects of a different subtype. + */ + private static Iterator createTypesafeIterator(final Iterator iterator) { + return new Iterator() { + public boolean hasNext() { + return iterator.hasNext(); + } + + public E next() { + return iterator.next(); + } + + public void remove() { + iterator.remove(); + } + }; + } + + /** the iterator being adapted into an iterable. */ + private final Iterator iterator; + + /** the iterator parameterized as the {@link #iterator()} return type. */ + private final Iterator typeSafeIterator; + + /** + * Constructs a new IteratorIterable that will use the given + * iterator. + * + * @param iterator the iterator to use. + */ + public IteratorIterable(final Iterator iterator) { + this(iterator, false); + } + + /** + * Constructs a new IteratorIterable that will use the given + * iterator. + * + * @param iterator the iterator to use. + * @param multipleUse true if the new iterable can be used in multiple iterations + */ + public IteratorIterable(final Iterator iterator, final boolean multipleUse) { + super(); + if (multipleUse && !(iterator instanceof ResettableIterator)) { + this.iterator = new ListIteratorWrapper(iterator); + } else { + this.iterator = iterator; + } + this.typeSafeIterator = createTypesafeIterator(this.iterator); + } + + /** + * Gets the iterator wrapped by this iterable. + * + * @return the iterator + */ + public Iterator iterator() { + if (iterator instanceof ResettableIterator) { + ((ResettableIterator)iterator).reset(); + } + return typeSafeIterator; + } +} diff --git a/src/org/apache/commons/collections4/iterators/LazyIteratorChain.java b/src/org/apache/commons/collections4/iterators/LazyIteratorChain.java new file mode 100644 index 0000000..818142c --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/LazyIteratorChain.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +/** + * An LazyIteratorChain is an Iterator that wraps a number of Iterators in a lazy manner. + *

              + * This class makes multiple iterators look like one to the caller. When any + * method from the Iterator interface is called, the LazyIteratorChain will delegate + * to a single underlying Iterator. The LazyIteratorChain will invoke the Iterators + * in sequence until all Iterators are exhausted. + *

              + * The Iterators are provided by {@link #nextIterator(int)} which has to be overridden by + * sub-classes and allows to lazily create the Iterators as they are accessed: + *

              + * return new LazyIteratorChain<String>() {
              + *     protected Iterator<String> nextIterator(int count) {
              + *         return count == 1 ? Arrays.asList("foo", "bar").iterator() : null;
              + *     }
              + * };
              + * 
              + *

              + * Once the inner Iterator's {@link Iterator#hasNext()} method returns false, + * {@link #nextIterator(int)} will be called to obtain another iterator, and so on + * until {@link #nextIterator(int)} returns null, indicating that the chain is exhausted. + *

              + * NOTE: The LazyIteratorChain may contain no iterators. In this case the class will + * function as an empty iterator. + * + * @since 4.0 + * @version $Id: LazyIteratorChain.java 1482073 2013-05-13 20:09:40Z tn $ + */ +public abstract class LazyIteratorChain implements Iterator { + + /** The number of times {@link #nextIterator()} was already called. */ + private int callCounter = 0; + + /** Indicates that the Iterator chain has been exhausted. */ + private boolean chainExhausted = false; + + /** The current iterator. */ + private Iterator currentIterator = null; + + /** + * The "last used" Iterator is the Iterator upon which next() or hasNext() + * was most recently called used for the remove() operation only. + */ + private Iterator lastUsedIterator = null; + + //----------------------------------------------------------------------- + + /** + * Gets the next iterator after the previous one has been exhausted. + *

              + * This method MUST return null when there are no more iterators. + * + * @param count the number of time this method has been called (starts with 1) + * @return the next iterator, or null if there are no more. + */ + protected abstract Iterator nextIterator(int count); + + /** + * Updates the current iterator field to ensure that the current Iterator + * is not exhausted. + */ + private void updateCurrentIterator() { + if (callCounter == 0) { + currentIterator = nextIterator(++callCounter); + if (currentIterator == null) { + currentIterator = EmptyIterator.emptyIterator(); + chainExhausted = true; + } + // set last used iterator here, in case the user calls remove + // before calling hasNext() or next() (although they shouldn't) + lastUsedIterator = currentIterator; + } + + while (currentIterator.hasNext() == false && !chainExhausted) { + final Iterator nextIterator = nextIterator(++callCounter); + if (nextIterator != null) { + currentIterator = nextIterator; + } else { + chainExhausted = true; + } + } + } + + //----------------------------------------------------------------------- + + /** + * Return true if any Iterator in the chain has a remaining element. + * + * @return true if elements remain + */ + public boolean hasNext() { + updateCurrentIterator(); + lastUsedIterator = currentIterator; + + return currentIterator.hasNext(); + } + + /** + * Returns the next element of the current Iterator + * + * @return element from the current Iterator + * @throws java.util.NoSuchElementException if all the Iterators are exhausted + */ + public E next() { + updateCurrentIterator(); + lastUsedIterator = currentIterator; + + return currentIterator.next(); + } + + /** + * Removes from the underlying collection the last element returned by the Iterator. + *

              + * As with next() and hasNext(), this method calls remove() on the underlying Iterator. + * Therefore, this method may throw an UnsupportedOperationException if the underlying + * Iterator does not support this method. + * + * @throws UnsupportedOperationException if the remove operator is not + * supported by the underlying Iterator + * @throws IllegalStateException if the next method has not yet been called, + * or the remove method has already been called after the last call to the next method. + */ + public void remove() { + if (currentIterator == null) { + updateCurrentIterator(); + } + lastUsedIterator.remove(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/ListIteratorWrapper.java b/src/org/apache/commons/collections4/iterators/ListIteratorWrapper.java new file mode 100644 index 0000000..1341051 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ListIteratorWrapper.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableListIterator; + +/** + * Converts an {@link Iterator} into a {@link ResettableListIterator}. + * For plain Iterators this is accomplished by caching the returned + * elements. This class can also be used to simply add + * {@link org.apache.commons.collections4.ResettableIterator ResettableIterator} + * functionality to a given {@link ListIterator}. + *

              + * The ListIterator interface has additional useful methods + * for navigation - previous() and the index methods. + * This class allows a regular Iterator to behave as a + * ListIterator. It achieves this by building a list internally + * of as the underlying iterator is traversed. + *

              + * The optional operations of ListIterator are not supported for plain Iterators. + *

              + * This class implements ResettableListIterator from Commons Collections 3.2. + * + * @since 2.1 + * @version $Id: ListIteratorWrapper.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public class ListIteratorWrapper implements ResettableListIterator { + + /** Message used when set or add are called. */ + private static final String UNSUPPORTED_OPERATION_MESSAGE = + "ListIteratorWrapper does not support optional operations of ListIterator."; + + /** Message used when set or add are called. */ + private static final String CANNOT_REMOVE_MESSAGE = "Cannot remove element at index {0}."; + + /** The underlying iterator being decorated. */ + private final Iterator iterator; + /** The list being used to cache the iterator. */ + private final List list = new ArrayList(); + + /** The current index of this iterator. */ + private int currentIndex = 0; + /** The current index of the wrapped iterator. */ + private int wrappedIteratorIndex = 0; + /** recall whether the wrapped iterator's "cursor" is in such a state as to allow remove() to be called */ + private boolean removeState; + + // Constructor + //------------------------------------------------------------------------- + /** + * Constructs a new ListIteratorWrapper that will wrap + * the given iterator. + * + * @param iterator the iterator to wrap + * @throws NullPointerException if the iterator is null + */ + public ListIteratorWrapper(final Iterator iterator) { + super(); + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + this.iterator = iterator; + } + + // ListIterator interface + //------------------------------------------------------------------------- + /** + * Throws {@link UnsupportedOperationException} + * unless the underlying Iterator is a ListIterator. + * + * @param obj the object to add + * @throws UnsupportedOperationException if the underlying iterator is not of + * type {@link ListIterator} + */ + public void add(final E obj) throws UnsupportedOperationException { + if (iterator instanceof ListIterator) { + @SuppressWarnings("unchecked") + final ListIterator li = (ListIterator) iterator; + li.add(obj); + return; + } + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE); + } + + /** + * Returns true if there are more elements in the iterator. + * + * @return true if there are more elements + */ + public boolean hasNext() { + if (currentIndex == wrappedIteratorIndex || iterator instanceof ListIterator) { + return iterator.hasNext(); + } + return true; + } + + /** + * Returns true if there are previous elements in the iterator. + * + * @return true if there are previous elements + */ + public boolean hasPrevious() { + if (iterator instanceof ListIterator) { + final ListIterator li = (ListIterator) iterator; + return li.hasPrevious(); + } + return currentIndex > 0; + } + + /** + * Returns the next element from the iterator. + * + * @return the next element from the iterator + * @throws NoSuchElementException if there are no more elements + */ + public E next() throws NoSuchElementException { + if (iterator instanceof ListIterator) { + return iterator.next(); + } + + if (currentIndex < wrappedIteratorIndex) { + ++currentIndex; + return list.get(currentIndex - 1); + } + + final E retval = iterator.next(); + list.add(retval); + ++currentIndex; + ++wrappedIteratorIndex; + removeState = true; + return retval; + } + + /** + * Returns the index of the next element. + * + * @return the index of the next element + */ + public int nextIndex() { + if (iterator instanceof ListIterator) { + final ListIterator li = (ListIterator) iterator; + return li.nextIndex(); + } + return currentIndex; + } + + /** + * Returns the the previous element. + * + * @return the previous element + * @throws NoSuchElementException if there are no previous elements + */ + public E previous() throws NoSuchElementException { + if (iterator instanceof ListIterator) { + @SuppressWarnings("unchecked") + final ListIterator li = (ListIterator) iterator; + return li.previous(); + } + + if (currentIndex == 0) { + throw new NoSuchElementException(); + } + removeState = wrappedIteratorIndex == currentIndex; + return list.get(--currentIndex); + } + + /** + * Returns the index of the previous element. + * + * @return the index of the previous element + */ + public int previousIndex() { + if (iterator instanceof ListIterator) { + final ListIterator li = (ListIterator) iterator; + return li.previousIndex(); + } + return currentIndex - 1; + } + + /** + * Throws {@link UnsupportedOperationException} if {@link #previous()} has ever been called. + * + * @throws UnsupportedOperationException always + */ + public void remove() throws UnsupportedOperationException { + if (iterator instanceof ListIterator) { + iterator.remove(); + return; + } + int removeIndex = currentIndex; + if (currentIndex == wrappedIteratorIndex) { + --removeIndex; + } + if (!removeState || wrappedIteratorIndex - currentIndex > 1) { + throw new IllegalStateException(MessageFormat.format(CANNOT_REMOVE_MESSAGE, Integer.valueOf(removeIndex))); + } + iterator.remove(); + list.remove(removeIndex); + currentIndex = removeIndex; + wrappedIteratorIndex--; + removeState = false; + } + + /** + * Throws {@link UnsupportedOperationException} + * unless the underlying Iterator is a ListIterator. + * + * @param obj the object to set + * @throws UnsupportedOperationException if the underlying iterator is not of + * type {@link ListIterator} + */ + public void set(final E obj) throws UnsupportedOperationException { + if (iterator instanceof ListIterator) { + @SuppressWarnings("unchecked") + final ListIterator li = (ListIterator) iterator; + li.set(obj); + return; + } + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE); + } + + // ResettableIterator interface + //------------------------------------------------------------------------- + /** + * Resets this iterator back to the position at which the iterator + * was created. + * + * @since 3.2 + */ + public void reset() { + if (iterator instanceof ListIterator) { + final ListIterator li = (ListIterator) iterator; + while (li.previousIndex() >= 0) { + li.previous(); + } + return; + } + currentIndex = 0; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/LoopingIterator.java b/src/org/apache/commons/collections4/iterators/LoopingIterator.java new file mode 100644 index 0000000..0a5ca4e --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/LoopingIterator.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableIterator; + +/** + * An Iterator that restarts when it reaches the end. + *

              + * The iterator will loop continuously around the provided elements, unless + * there are no elements in the collection to begin with, or all the elements + * have been {@link #remove removed}. + *

              + * Concurrent modifications are not directly supported, and for most collection + * implementations will throw a ConcurrentModificationException. + * + * @since 3.0 + * @version $Id: LoopingIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public class LoopingIterator implements ResettableIterator { + + /** The collection to base the iterator on */ + private final Collection collection; + /** The current iterator */ + private Iterator iterator; + + /** + * Constructor that wraps a collection. + *

              + * There is no way to reset an Iterator instance without recreating it from + * the original source, so the Collection must be passed in. + * + * @param coll the collection to wrap + * @throws NullPointerException if the collection is null + */ + public LoopingIterator(final Collection coll) { + if (coll == null) { + throw new NullPointerException("The collection must not be null"); + } + collection = coll; + reset(); + } + + /** + * Has the iterator any more elements. + *

              + * Returns false only if the collection originally had zero elements, or + * all the elements have been {@link #remove removed}. + * + * @return true if there are more elements + */ + public boolean hasNext() { + return collection.size() > 0; + } + + /** + * Returns the next object in the collection. + *

              + * If at the end of the collection, return the first element. + * + * @return the next object + * @throws NoSuchElementException if there are no elements + * at all. Use {@link #hasNext} to avoid this error. + */ + public E next() { + if (collection.size() == 0) { + throw new NoSuchElementException("There are no elements for this iterator to loop on"); + } + if (iterator.hasNext() == false) { + reset(); + } + return iterator.next(); + } + + /** + * Removes the previously retrieved item from the underlying collection. + *

              + * This feature is only supported if the underlying collection's + * {@link Collection#iterator iterator} method returns an implementation + * that supports it. + *

              + * This method can only be called after at least one {@link #next} method call. + * After a removal, the remove method may not be called again until another + * next has been performed. If the {@link #reset} is called, then remove may + * not be called until {@link #next} is called again. + */ + public void remove() { + iterator.remove(); + } + + /** + * Resets the iterator back to the start of the collection. + */ + public void reset() { + iterator = collection.iterator(); + } + + /** + * Gets the size of the collection underlying the iterator. + * + * @return the current collection size + */ + public int size() { + return collection.size(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/LoopingListIterator.java b/src/org/apache/commons/collections4/iterators/LoopingListIterator.java new file mode 100644 index 0000000..cdefbd6 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/LoopingListIterator.java @@ -0,0 +1,254 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableListIterator; + +/** + * A ListIterator that restarts when it reaches the end or when it + * reaches the beginning. + *

              + * The iterator will loop continuously around the provided list, + * unless there are no elements in the collection to begin with, or + * all of the elements have been {@link #remove removed}. + *

              + * Concurrent modifications are not directly supported, and for most + * collection implementations will throw a + * ConcurrentModificationException. + * + * @since 3.2 + * @version $Id: LoopingListIterator.java 1494333 2013-06-18 21:59:21Z sebb $ + */ +public class LoopingListIterator implements ResettableListIterator { + + /** The list to base the iterator on */ + private final List list; + /** The current list iterator */ + private ListIterator iterator; + + /** + * Constructor that wraps a list. + *

              + * There is no way to reset a ListIterator instance without + * recreating it from the original source, so the List must be + * passed in and a reference to it held. + * + * @param list the list to wrap + * @throws NullPointerException if the list it null + */ + public LoopingListIterator(final List list) { + if (list == null) { + throw new NullPointerException("The list must not be null"); + } + this.list = list; + _reset(); + } + + /** + * Returns whether this iterator has any more elements. + *

              + * Returns false only if the list originally had zero elements, or + * all elements have been {@link #remove removed}. + * + * @return true if there are more elements + */ + public boolean hasNext() { + return !list.isEmpty(); + } + + /** + * Returns the next object in the list. + *

              + * If at the end of the list, returns the first element. + * + * @return the object after the last element returned + * @throws NoSuchElementException if there are no elements in the list + */ + public E next() { + if (list.isEmpty()) { + throw new NoSuchElementException( + "There are no elements for this iterator to loop on"); + } + if (iterator.hasNext() == false) { + reset(); + } + return iterator.next(); + } + + /** + * Returns the index of the element that would be returned by a + * subsequent call to {@link #next}. + *

              + * As would be expected, if the iterator is at the physical end of + * the underlying list, 0 is returned, signifying the beginning of + * the list. + * + * @return the index of the element that would be returned if next() were called + * @throws NoSuchElementException if there are no elements in the list + */ + public int nextIndex() { + if (list.isEmpty()) { + throw new NoSuchElementException( + "There are no elements for this iterator to loop on"); + } + if (iterator.hasNext() == false) { + return 0; + } + return iterator.nextIndex(); + } + + /** + * Returns whether this iterator has any more previous elements. + *

              + * Returns false only if the list originally had zero elements, or + * all elements have been {@link #remove removed}. + * + * @return true if there are more elements + */ + public boolean hasPrevious() { + return !list.isEmpty(); + } + + /** + * Returns the previous object in the list. + *

              + * If at the beginning of the list, return the last element. Note + * that in this case, traversal to find that element takes linear time. + * + * @return the object before the last element returned + * @throws NoSuchElementException if there are no elements in the list + */ + public E previous() { + if (list.isEmpty()) { + throw new NoSuchElementException( + "There are no elements for this iterator to loop on"); + } + if (iterator.hasPrevious() == false) { + E result = null; + while (iterator.hasNext()) { + result = iterator.next(); + } + iterator.previous(); + return result; + } + return iterator.previous(); + } + + /** + * Returns the index of the element that would be returned by a + * subsequent call to {@link #previous}. + *

              + * As would be expected, if at the iterator is at the physical + * beginning of the underlying list, the list's size minus one is + * returned, signifying the end of the list. + * + * @return the index of the element that would be returned if previous() were called + * @throws NoSuchElementException if there are no elements in the list + */ + public int previousIndex() { + if (list.isEmpty()) { + throw new NoSuchElementException( + "There are no elements for this iterator to loop on"); + } + if (iterator.hasPrevious() == false) { + return list.size() - 1; + } + return iterator.previousIndex(); + } + + /** + * Removes the previously retrieved item from the underlying list. + *

              + * This feature is only supported if the underlying list's + * {@link List#iterator iterator} method returns an implementation + * that supports it. + *

              + * This method can only be called after at least one {@link #next} + * or {@link #previous} method call. After a removal, the remove + * method may not be called again until another {@link #next} or + * {@link #previous} has been performed. If the {@link #reset} is + * called, then remove may not be called until {@link #next} or + * {@link #previous} is called again. + * + * @throws UnsupportedOperationException if the remove method is + * not supported by the iterator implementation of the underlying + * list + */ + public void remove() { + iterator.remove(); + } + + /** + * Inserts the specified element into the underlying list. + *

              + * The element is inserted before the next element that would be + * returned by {@link #next}, if any, and after the next element + * that would be returned by {@link #previous}, if any. + *

              + * This feature is only supported if the underlying list's + * {@link List#listIterator} method returns an implementation + * that supports it. + * + * @param obj the element to insert + * @throws UnsupportedOperationException if the add method is not + * supported by the iterator implementation of the underlying list + */ + public void add(final E obj) { + iterator.add(obj); + } + + /** + * Replaces the last element that was returned by {@link #next} or + * {@link #previous}. + *

              + * This feature is only supported if the underlying list's + * {@link List#listIterator} method returns an implementation + * that supports it. + * + * @param obj the element with which to replace the last element returned + * @throws UnsupportedOperationException if the set method is not + * supported by the iterator implementation of the underlying list + */ + public void set(final E obj) { + iterator.set(obj); + } + + /** + * Resets the iterator back to the start of the list. + */ + public void reset() { + _reset(); + } + + private void _reset() { + iterator = list.listIterator(); + } + + /** + * Gets the size of the list underlying the iterator. + * + * @return the current list size + */ + public int size() { + return list.size(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/NodeListIterator.java b/src/org/apache/commons/collections4/iterators/NodeListIterator.java new file mode 100644 index 0000000..a5c1575 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/NodeListIterator.java @@ -0,0 +1,88 @@ +/* + * Copyright 2013 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * An {@link Iterator} over a {@link NodeList}. + *

              + * This iterator does not support {@link #remove()} as a {@link NodeList} does not support + * removal of items. + * + * @since 4.0 + * @version $Id: NodeListIterator.java 1686855 2015-06-22 13:00:27Z tn $ + * @see NodeList + */ +public class NodeListIterator implements Iterator { + + /** the original NodeList instance */ + private final NodeList nodeList; + /** The current iterator index */ + private int index = 0; + + /** + * Convenience constructor, which creates a new NodeListIterator from + * the specified node's childNodes. + * + * @param node Node, who's child nodes are wrapped by this class. Must not be null + * @throws NullPointerException if node is null + */ + public NodeListIterator(final Node node) { + if (node == null) { + throw new NullPointerException("Node must not be null."); + } + this.nodeList = node.getChildNodes(); + } + + /** + * Constructor, that creates a new NodeListIterator from the specified + * org.w3c.NodeList + * + * @param nodeList node list, which is wrapped by this class. Must not be null + * @throws NullPointerException if nodeList is null + */ + public NodeListIterator(final NodeList nodeList) { + if (nodeList == null) { + throw new NullPointerException("NodeList must not be null."); + } + this.nodeList = nodeList; + } + + public boolean hasNext() { + return nodeList == null ? false : index < nodeList.getLength(); + } + + public Node next() { + if (nodeList != null && index < nodeList.getLength()) { + return nodeList.item(index++); + } + throw new NoSuchElementException("underlying nodeList has no more elements"); + } + + /** + * Throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException always + */ + public void remove() { + throw new UnsupportedOperationException("remove() method not supported for a NodeListIterator."); + } +} diff --git a/src/org/apache/commons/collections4/iterators/ObjectArrayIterator.java b/src/org/apache/commons/collections4/iterators/ObjectArrayIterator.java new file mode 100644 index 0000000..6bd637e --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ObjectArrayIterator.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableIterator; + +/** + * An {@link Iterator} over an array of objects. + *

              + * This iterator does not support {@link #remove}, as the object array cannot be + * structurally modified. + *

              + * The iterator implements a {@link #reset} method, allowing the reset of the iterator + * back to the start if required. + * + * @since 3.0 + * @version $Id: ObjectArrayIterator.java 1543928 2013-11-20 20:15:35Z tn $ + */ +public class ObjectArrayIterator implements ResettableIterator { + + /** The array */ + final E[] array; + /** The start index to loop from */ + final int startIndex; + /** The end index to loop to */ + final int endIndex; + /** The current iterator index */ + int index = 0; + + //------------------------------------------------------------------------- + /** + * Constructs an ObjectArrayIterator that will iterate over the values in the + * specified array. + * + * @param array the array to iterate over + * @throws NullPointerException if array is null + */ + @SafeVarargs + public ObjectArrayIterator(final E... array) { + this(array, 0, array.length); + } + + /** + * Constructs an ObjectArrayIterator that will iterate over the values in the + * specified array from a specific start index. + * + * @param array the array to iterate over + * @param start the index to start iterating at + * @throws NullPointerException if array is null + * @throws IndexOutOfBoundsException if the start index is out of bounds + */ + public ObjectArrayIterator(final E array[], final int start) { + this(array, start, array.length); + } + + /** + * Construct an ObjectArrayIterator that will iterate over a range of values + * in the specified array. + * + * @param array the array to iterate over + * @param start the index to start iterating at + * @param end the index (exclusive) to finish iterating at + * @throws IndexOutOfBoundsException if the start or end index is out of bounds + * @throws IllegalArgumentException if end index is before the start + * @throws NullPointerException if array is null + */ + public ObjectArrayIterator(final E array[], final int start, final int end) { + super(); + if (start < 0) { + throw new ArrayIndexOutOfBoundsException("Start index must not be less than zero"); + } + if (end > array.length) { + throw new ArrayIndexOutOfBoundsException("End index must not be greater than the array length"); + } + if (start > array.length) { + throw new ArrayIndexOutOfBoundsException("Start index must not be greater than the array length"); + } + if (end < start) { + throw new IllegalArgumentException("End index must not be less than start index"); + } + this.array = array; + this.startIndex = start; + this.endIndex = end; + this.index = start; + } + + // Iterator interface + //------------------------------------------------------------------------- + + /** + * Returns true if there are more elements to return from the array. + * + * @return true if there is a next element to return + */ + public boolean hasNext() { + return this.index < this.endIndex; + } + + /** + * Returns the next element in the array. + * + * @return the next element in the array + * @throws NoSuchElementException if all the elements in the array + * have already been returned + */ + public E next() { + if (hasNext() == false) { + throw new NoSuchElementException(); + } + return this.array[this.index++]; + } + + /** + * Throws {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException always + */ + public void remove() { + throw new UnsupportedOperationException("remove() method is not supported for an ObjectArrayIterator"); + } + + // Properties + //------------------------------------------------------------------------- + + /** + * Gets the array that this iterator is iterating over. + * + * @return the array this iterator iterates over + */ + public E[] getArray() { + return this.array; + } + + /** + * Gets the start index to loop from. + * + * @return the start index + */ + public int getStartIndex() { + return this.startIndex; + } + + /** + * Gets the end index to loop to. + * + * @return the end index + */ + public int getEndIndex() { + return this.endIndex; + } + + /** + * Resets the iterator back to the start index. + */ + public void reset() { + this.index = this.startIndex; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/ObjectArrayListIterator.java b/src/org/apache/commons/collections4/iterators/ObjectArrayListIterator.java new file mode 100644 index 0000000..c48b02f --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ObjectArrayListIterator.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableListIterator; + +/** + * Implements a {@link ListIterator} over an array of objects. + *

              + * This iterator does not support {@link #add} or {@link #remove}, as the object array + * cannot be structurally modified. The {@link #set} method is supported however. + *

              + * The iterator implements a {@link #reset} method, allowing the reset of the iterator + * back to the start if required. + * + * @see org.apache.commons.collections4.iterators.ObjectArrayIterator + * @see java.util.Iterator + * @see java.util.ListIterator + * + * @since 3.0 + * @version $Id: ObjectArrayListIterator.java 1543928 2013-11-20 20:15:35Z tn $ + */ +public class ObjectArrayListIterator extends ObjectArrayIterator + implements ResettableListIterator { + + /** + * Holds the index of the last item returned by a call to next() + * or previous(). This is set to -1 if neither method + * has yet been invoked. lastItemIndex is used to to implement the + * {@link #set} method. + */ + private int lastItemIndex = -1; + + //------------------------------------------------------------------------- + /** + * Constructs an ObjectArrayListIterator that will iterate over the values in the + * specified array. + * + * @param array the array to iterate over + * @throws NullPointerException if array is null + */ + @SafeVarargs + public ObjectArrayListIterator(final E... array) { + super(array); + } + + /** + * Constructs an ObjectArrayListIterator that will iterate over the values in the + * specified array from a specific start index. + * + * @param array the array to iterate over + * @param start the index to start iterating at + * @throws NullPointerException if array is null + * @throws IndexOutOfBoundsException if the start index is out of bounds + */ + public ObjectArrayListIterator(final E[] array, final int start) { + super(array, start); + } + + /** + * Construct an ObjectArrayListIterator that will iterate over a range of values + * in the specified array. + * + * @param array the array to iterate over + * @param start the index to start iterating at + * @param end the index (exclusive) to finish iterating at + * @throws IndexOutOfBoundsException if the start or end index is out of bounds + * @throws IllegalArgumentException if end index is before the start + * @throws NullPointerException if array is null + */ + public ObjectArrayListIterator(final E[] array, final int start, final int end) { + super(array, start, end); + } + + // ListIterator interface + //------------------------------------------------------------------------- + + /** + * Returns true if there are previous elements to return from the array. + * + * @return true if there is a previous element to return + */ + public boolean hasPrevious() { + return this.index > getStartIndex(); + } + + /** + * Gets the previous element from the array. + * + * @return the previous element + * @throws NoSuchElementException if there is no previous element + */ + public E previous() { + if (hasPrevious() == false) { + throw new NoSuchElementException(); + } + this.lastItemIndex = --this.index; + return this.array[this.index]; + } + + /** + * Gets the next element from the array. + * + * @return the next element + * @throws NoSuchElementException if there is no next element + */ + @Override + public E next() { + if (hasNext() == false) { + throw new NoSuchElementException(); + } + this.lastItemIndex = this.index; + return this.array[this.index++]; + } + + /** + * Gets the next index to be retrieved. + * + * @return the index of the item to be retrieved next + */ + public int nextIndex() { + return this.index - getStartIndex(); + } + + /** + * Gets the index of the item to be retrieved if {@link #previous()} is called. + * + * @return the index of the item to be retrieved next + */ + public int previousIndex() { + return this.index - getStartIndex() - 1; + } + + /** + * This iterator does not support modification of its backing array's size, and so will + * always throw an {@link UnsupportedOperationException} when this method is invoked. + * + * @param obj the object to add + * @throws UnsupportedOperationException always thrown. + */ + public void add(final E obj) { + throw new UnsupportedOperationException("add() method is not supported"); + } + + /** + * Sets the element under the cursor. + *

              + * This method sets the element that was returned by the last call + * to {@link #next()} of {@link #previous()}. + * + * Note: {@link ListIterator} implementations that support add() + * and remove() only allow set() to be called once per call + * to next() or previous (see the {@link ListIterator} + * javadoc for more details). Since this implementation does not support + * add() or remove(), set() may be + * called as often as desired. + * + * @param obj the object to set into the array + * @throws IllegalStateException if next() has not yet been called. + * @throws ClassCastException if the object type is unsuitable for the array + */ + public void set(final E obj) { + if (this.lastItemIndex == -1) { + throw new IllegalStateException("must call next() or previous() before a call to set()"); + } + + this.array[this.lastItemIndex] = obj; + } + + /** + * Resets the iterator back to the start index. + */ + @Override + public void reset() { + super.reset(); + this.lastItemIndex = -1; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/ObjectGraphIterator.java b/src/org/apache/commons/collections4/iterators/ObjectGraphIterator.java new file mode 100644 index 0000000..d8b950c --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ObjectGraphIterator.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.Transformer; + +/** + * An Iterator that can traverse multiple iterators down an object graph. + *

              + * This iterator can extract multiple objects from a complex tree-like object graph. + * The iteration starts from a single root object. + * It uses a Transformer to extract the iterators and elements. + * Its main benefit is that no intermediate List is created. + *

              + * For example, consider an object graph: + *

              + *                 |- Branch -- Leaf
              + *                 |         \- Leaf
              + *         |- Tree |         /- Leaf
              + *         |       |- Branch -- Leaf
              + *  Forest |                 \- Leaf
              + *         |       |- Branch -- Leaf
              + *         |       |         \- Leaf
              + *         |- Tree |         /- Leaf
              + *                 |- Branch -- Leaf
              + *                 |- Branch -- Leaf
              + * The following Transformer, used in this class, will extract all + * the Leaf objects without creating a combined intermediate list: + *
              + * public Object transform(Object input) {
              + *   if (input instanceof Forest) {
              + *     return ((Forest) input).treeIterator();
              + *   }
              + *   if (input instanceof Tree) {
              + *     return ((Tree) input).branchIterator();
              + *   }
              + *   if (input instanceof Branch) {
              + *     return ((Branch) input).leafIterator();
              + *   }
              + *   if (input instanceof Leaf) {
              + *     return input;
              + *   }
              + *   throw new ClassCastException();
              + * }
              + *

              + * Internally, iteration starts from the root object. When next is called, + * the transformer is called to examine the object. The transformer will return + * either an iterator or an object. If the object is an Iterator, the next element + * from that iterator is obtained and the process repeats. If the element is an object + * it is returned. + *

              + * Under many circumstances, linking Iterators together in this manner is + * more efficient (and convenient) than using nested for loops to extract a list. + * + * @since 3.1 + * @version $Id: ObjectGraphIterator.java 1681434 2015-05-24 10:49:58Z tn $ + */ +public class ObjectGraphIterator implements Iterator { + + /** The stack of iterators */ + private final Deque> stack = new ArrayDeque>(8); + /** The root object in the tree */ + private E root; + /** The transformer to use */ + private final Transformer transformer; + + /** Whether there is another element in the iteration */ + private boolean hasNext = false; + /** The current iterator */ + private Iterator currentIterator; + /** The current value */ + private E currentValue; + /** The last used iterator, needed for remove() */ + private Iterator lastUsedIterator; + + //----------------------------------------------------------------------- + /** + * Constructs an ObjectGraphIterator using a root object and transformer. + *

              + * The root object can be an iterator, in which case it will be immediately + * looped around. + * + * @param root the root object, null will result in an empty iterator + * @param transformer the transformer to use, null will use a no effect transformer + */ + @SuppressWarnings("unchecked") + public ObjectGraphIterator(final E root, final Transformer transformer) { + super(); + if (root instanceof Iterator) { + this.currentIterator = (Iterator) root; + } else { + this.root = root; + } + this.transformer = transformer; + } + + /** + * Constructs a ObjectGraphIterator that will handle an iterator of iterators. + *

              + * This constructor exists for convenience to emphasise that this class can + * be used to iterate over nested iterators. That is to say that the iterator + * passed in here contains other iterators, which may in turn contain further + * iterators. + * + * @param rootIterator the root iterator, null will result in an empty iterator + */ + public ObjectGraphIterator(final Iterator rootIterator) { + super(); + this.currentIterator = rootIterator; + this.transformer = null; + } + + //----------------------------------------------------------------------- + /** + * Loops around the iterators to find the next value to return. + */ + protected void updateCurrentIterator() { + if (hasNext) { + return; + } + if (currentIterator == null) { + if (root == null) { // NOPMD + // do nothing, hasNext will be false + } else { + if (transformer == null) { + findNext(root); + } else { + findNext(transformer.transform(root)); + } + root = null; + } + } else { + findNextByIterator(currentIterator); + } + } + + /** + * Finds the next object in the iteration given any start object. + * + * @param value the value to start from + */ + @SuppressWarnings("unchecked") + protected void findNext(final E value) { + if (value instanceof Iterator) { + // need to examine this iterator + findNextByIterator((Iterator) value); + } else { + // next value found + currentValue = value; + hasNext = true; + } + } + + /** + * Finds the next object in the iteration given an iterator. + * + * @param iterator the iterator to start from + */ + protected void findNextByIterator(final Iterator iterator) { + if (iterator != currentIterator) { + // recurse a level + if (currentIterator != null) { + stack.push(currentIterator); + } + currentIterator = iterator; + } + + while (currentIterator.hasNext() && hasNext == false) { + E next = currentIterator.next(); + if (transformer != null) { + next = transformer.transform(next); + } + findNext(next); + } + // if we havn't found the next value and iterators are not yet exhausted + if (!hasNext && !stack.isEmpty()) { + // current iterator exhausted, go up a level + currentIterator = stack.pop(); + findNextByIterator(currentIterator); + } + } + + //----------------------------------------------------------------------- + /** + * Checks whether there are any more elements in the iteration to obtain. + * + * @return true if elements remain in the iteration + */ + public boolean hasNext() { + updateCurrentIterator(); + return hasNext; + } + + /** + * Gets the next element of the iteration. + * + * @return the next element from the iteration + * @throws NoSuchElementException if all the Iterators are exhausted + */ + public E next() { + updateCurrentIterator(); + if (hasNext == false) { + throw new NoSuchElementException("No more elements in the iteration"); + } + lastUsedIterator = currentIterator; + final E result = currentValue; + currentValue = null; + hasNext = false; + return result; + } + + /** + * Removes from the underlying collection the last element returned. + *

              + * This method calls remove() on the underlying Iterator and it may + * throw an UnsupportedOperationException if the underlying Iterator + * does not support this method. + * + * @throws UnsupportedOperationException + * if the remove operator is not supported by the underlying Iterator + * @throws IllegalStateException + * if the next method has not yet been called, or the remove method has + * already been called after the last call to the next method. + */ + public void remove() { + if (lastUsedIterator == null) { + throw new IllegalStateException("Iterator remove() cannot be called at this time"); + } + lastUsedIterator.remove(); + lastUsedIterator = null; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/PeekingIterator.java b/src/org/apache/commons/collections4/iterators/PeekingIterator.java new file mode 100644 index 0000000..080398f --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/PeekingIterator.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Decorates an iterator to support one-element lookahead while iterating. + *

              + * The decorator supports the removal operation, but an {@link IllegalStateException} + * will be thrown if {@link #remove()} is called directly after a call to + * {@link #peek()} or {@link #element()}. + * + * @since 4.0 + * @version $Id: PeekingIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PeekingIterator implements Iterator { + + /** The iterator being decorated. */ + private final Iterator iterator; + + /** Indicates that the decorated iterator is exhausted. */ + private boolean exhausted = false; + + /** Indicates if the lookahead slot is filled. */ + private boolean slotFilled = false; + + /** The current slot for lookahead. */ + private E slot; + + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator to support one-element lookahead. + *

              + * If the iterator is already a {@link PeekingIterator} it is returned directly. + * + * @param the element type + * @param iterator the iterator to decorate + * @return a new peeking iterator + * @throws NullPointerException if the iterator is null + */ + public static PeekingIterator peekingIterator(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (iterator instanceof PeekingIterator) { + @SuppressWarnings("unchecked") // safe cast + final PeekingIterator it = (PeekingIterator) iterator; + return it; + } + return new PeekingIterator(iterator); + } + + //----------------------------------------------------------------------- + + /** + * Constructor. + * + * @param iterator the iterator to decorate + */ + public PeekingIterator(final Iterator iterator) { + this.iterator = iterator; + } + + private void fill() { + if (exhausted || slotFilled) { + return; + } + if (iterator.hasNext()) { + slot = iterator.next(); + slotFilled = true; + } else { + exhausted = true; + slot = null; + slotFilled = false; + } + } + + //----------------------------------------------------------------------- + public boolean hasNext() { + if (exhausted) { + return false; + } + return slotFilled ? true : iterator.hasNext(); + } + + /** + * Returns the next element in iteration without advancing the underlying iterator. + * If the iterator is already exhausted, null will be returned. + *

              + * Note: this method does not throw a {@link NoSuchElementException} if the iterator + * is already exhausted. If you want such a behavior, use {@link #element()} instead. + *

              + * The rationale behind this is to follow the {@link java.util.Queue} interface + * which uses the same terminology. + * + * @return the next element from the iterator + */ + public E peek() { + fill(); + return exhausted ? null : slot; + } + + /** + * Returns the next element in iteration without advancing the underlying iterator. + * If the iterator is already exhausted, null will be returned. + * + * @return the next element from the iterator + * @throws NoSuchElementException if the iterator is already exhausted according to {@link #hasNext()} + */ + public E element() { + fill(); + if (exhausted) { + throw new NoSuchElementException(); + } + return slot; + } + + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + final E x = slotFilled ? slot : iterator.next(); + // reset the lookahead slot + slot = null; + slotFilled = false; + return x; + } + + /** + * {@inheritDoc} + * + * @throws IllegalStateException if {@link #peek()} or {@link #element()} has been called + * prior to the call to {@link #remove()} + */ + public void remove() { + if (slotFilled) { + throw new IllegalStateException("peek() or element() called before remove()"); + } + iterator.remove(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/PermutationIterator.java b/src/org/apache/commons/collections4/iterators/PermutationIterator.java new file mode 100644 index 0000000..8193ead --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/PermutationIterator.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +/** + * This iterator creates permutations of an input collection, using the + * Steinhaus-Johnson-Trotter algorithm (also called plain changes). + *

              + * The iterator will return exactly n! permutations of the input collection. + * The {@code remove()} operation is not supported, and will throw an + * {@code UnsupportedOperationException}. + *

              + * NOTE: in case an empty collection is provided, the iterator will + * return exactly one empty list as result, as 0! = 1. + * + * @param the type of the objects being permuted + * + * @version $Id: PermutationIterator.java 1533984 2013-10-20 21:12:51Z tn $ + * @since 4.0 + */ +public class PermutationIterator implements Iterator> { + + /** + * Permutation is done on theses keys to handle equal objects. + */ + private int[] keys; + + /** + * Mapping between keys and objects. + */ + private Map objectMap; + + /** + * Direction table used in the algorithm: + *

                + *
              • false is left
              • + *
              • true is right
              • + *
              + */ + private boolean[] direction; + + /** + * Next permutation to return. When a permutation is requested + * this instance is provided and the next one is computed. + */ + private List nextPermutation; + + /** + * Standard constructor for this class. + * @param coll the collection to generate permutations for + * @throws NullPointerException if coll is null + */ + public PermutationIterator(final Collection coll) { + if (coll == null) { + throw new NullPointerException("The collection must not be null"); + } + + keys = new int[coll.size()]; + direction = new boolean[coll.size()]; + Arrays.fill(direction, false); + int value = 1; + objectMap = new HashMap(); + for (E e : coll) { + objectMap.put(Integer.valueOf(value), e); + keys[value - 1] = value; + value++; + } + nextPermutation = new ArrayList(coll); + } + + /** + * Indicates if there are more permutation available. + * @return true if there are more permutations, otherwise false + */ + public boolean hasNext() { + return nextPermutation != null; + } + + /** + * Returns the next permutation of the input collection. + * @return a list of the permutator's elements representing a permutation + * @throws NoSuchElementException if there are no more permutations + */ + public List next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + // find the largest mobile integer k + int indexOfLargestMobileInteger = -1; + int largestKey = -1; + for (int i = 0; i < keys.length; i++) { + if ((direction[i] && i < keys.length - 1 && keys[i] > keys[i + 1]) || + (!direction[i] && i > 0 && keys[i] > keys[i - 1])) { + if (keys[i] > largestKey) { + largestKey = keys[i]; + indexOfLargestMobileInteger = i; + } + } + } + if (largestKey == -1) { + List toReturn = nextPermutation; + nextPermutation = null; + return toReturn; + } + + // swap k and the adjacent integer it is looking at + final int offset = direction[indexOfLargestMobileInteger] ? 1 : -1; + final int tmpKey = keys[indexOfLargestMobileInteger]; + keys[indexOfLargestMobileInteger] = keys[indexOfLargestMobileInteger + offset]; + keys[indexOfLargestMobileInteger + offset] = tmpKey; + boolean tmpDirection = direction[indexOfLargestMobileInteger]; + direction[indexOfLargestMobileInteger] = direction[indexOfLargestMobileInteger + offset]; + direction[indexOfLargestMobileInteger + offset] = tmpDirection; + + // reverse the direction of all integers larger than k and build the result + final List nextP = new ArrayList(); + for (int i = 0; i < keys.length; i++) { + if (keys[i] > largestKey) { + direction[i] = !direction[i]; + } + nextP.add(objectMap.get(Integer.valueOf(keys[i]))); + } + final List result = nextPermutation; + nextPermutation = nextP; + return result; + } + + public void remove() { + throw new UnsupportedOperationException("remove() is not supported"); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/PushbackIterator.java b/src/org/apache/commons/collections4/iterators/PushbackIterator.java new file mode 100644 index 0000000..a177955 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/PushbackIterator.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; + +/** + * Decorates an iterator to support pushback of elements. + *

              + * The decorator stores the pushed back elements in a LIFO manner: the last element + * that has been pushed back, will be returned as the next element in a call to {@link #next()}. + *

              + * The decorator does not support the removal operation. Any call to {@link #remove()} will + * result in an {@link UnsupportedOperationException}. + * + * @since 4.0 + * @version $Id: PushbackIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PushbackIterator implements Iterator { + + /** The iterator being decorated. */ + private final Iterator iterator; + + /** The LIFO queue containing the pushed back items. */ + private Deque items = new ArrayDeque(); + + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator to support one-element lookahead. + *

              + * If the iterator is already a {@link PushbackIterator} it is returned directly. + * + * @param the element type + * @param iterator the iterator to decorate + * @return a new peeking iterator + * @throws NullPointerException if the iterator is null + */ + public static PushbackIterator pushbackIterator(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (iterator instanceof PushbackIterator) { + @SuppressWarnings("unchecked") // safe cast + final PushbackIterator it = (PushbackIterator) iterator; + return it; + } + return new PushbackIterator(iterator); + } + + //----------------------------------------------------------------------- + + /** + * Constructor. + * + * @param iterator the iterator to decorate + */ + public PushbackIterator(final Iterator iterator) { + super(); + this.iterator = iterator; + } + + /** + * Push back the given element to the iterator. + *

              + * Calling {@link #next()} immediately afterwards will return exactly this element. + * + * @param item the element to push back to the iterator + */ + public void pushback(final E item) { + items.push(item); + } + + public boolean hasNext() { + return !items.isEmpty() ? true : iterator.hasNext(); + } + + public E next() { + return !items.isEmpty() ? items.pop() : iterator.next(); + } + + /** + * This iterator will always throw an {@link UnsupportedOperationException}. + * + * @throws UnsupportedOperationException always + */ + public void remove() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/ReverseListIterator.java b/src/org/apache/commons/collections4/iterators/ReverseListIterator.java new file mode 100644 index 0000000..fdbc50f --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ReverseListIterator.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.collections4.ResettableListIterator; + +/** + * Iterates backwards through a List, starting with the last element + * and continuing to the first. This is useful for looping around + * a list in reverse order without needing to actually reverse the list. + *

              + * The first call to next() will return the last element + * from the list, and so on. The hasNext() method works + * in concert with the next() method as expected. + * However, the nextIndex() method returns the correct + * index in the list, thus it starts high and reduces as the iteration + * continues. The previous methods work similarly. + * + * @since 3.2 + * @version $Id: ReverseListIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ReverseListIterator implements ResettableListIterator { + + /** The list being wrapped. */ + private final List list; + /** The list iterator being wrapped. */ + private ListIterator iterator; + /** Flag to indicate if updating is possible at the moment. */ + private boolean validForUpdate = true; + + /** + * Constructor that wraps a list. + * + * @param list the list to create a reversed iterator for + * @throws NullPointerException if the list is null + */ + public ReverseListIterator(final List list) { + super(); + if (list == null) { + throw new NullPointerException("List must not be null."); + } + this.list = list; + iterator = list.listIterator(list.size()); + } + + //----------------------------------------------------------------------- + /** + * Checks whether there is another element. + * + * @return true if there is another element + */ + public boolean hasNext() { + return iterator.hasPrevious(); + } + + /** + * Gets the next element. + * The next element is the previous in the list. + * + * @return the next element in the iterator + */ + public E next() { + final E obj = iterator.previous(); + validForUpdate = true; + return obj; + } + + /** + * Gets the index of the next element. + * + * @return the index of the next element in the iterator + */ + public int nextIndex() { + return iterator.previousIndex(); + } + + /** + * Checks whether there is a previous element. + * + * @return true if there is a previous element + */ + public boolean hasPrevious() { + return iterator.hasNext(); + } + + /** + * Gets the previous element. + * The next element is the previous in the list. + * + * @return the previous element in the iterator + */ + public E previous() { + final E obj = iterator.next(); + validForUpdate = true; + return obj; + } + + /** + * Gets the index of the previous element. + * + * @return the index of the previous element in the iterator + */ + public int previousIndex() { + return iterator.nextIndex(); + } + + /** + * Removes the last returned element. + * + * @throws UnsupportedOperationException if the list is unmodifiable + * @throws IllegalStateException if there is no element to remove + */ + public void remove() { + if (validForUpdate == false) { + throw new IllegalStateException("Cannot remove from list until next() or previous() called"); + } + iterator.remove(); + } + + /** + * Replaces the last returned element. + * + * @param obj the object to set + * @throws UnsupportedOperationException if the list is unmodifiable + * @throws IllegalStateException if the iterator is not in a valid state for set + */ + public void set(final E obj) { + if (validForUpdate == false) { + throw new IllegalStateException("Cannot set to list until next() or previous() called"); + } + iterator.set(obj); + } + + /** + * Adds a new element to the list between the next and previous elements. + * + * @param obj the object to add + * @throws UnsupportedOperationException if the list is unmodifiable + * @throws IllegalStateException if the iterator is not in a valid state for set + */ + public void add(final E obj) { + // the validForUpdate flag is needed as the necessary previous() + // method call re-enables remove and add + if (validForUpdate == false) { + throw new IllegalStateException("Cannot add to list until next() or previous() called"); + } + validForUpdate = false; + iterator.add(obj); + iterator.previous(); + } + + /** + * Resets the iterator back to the start (which is the + * end of the list as this is a reversed iterator) + */ + public void reset() { + iterator = list.listIterator(list.size()); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/SingletonIterator.java b/src/org/apache/commons/collections4/iterators/SingletonIterator.java new file mode 100644 index 0000000..5260695 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/SingletonIterator.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableIterator; + +/** + * SingletonIterator is an {@link Iterator} over a single + * object instance. + * + * @since 2.0 + * @version $Id: SingletonIterator.java 1612021 2014-07-20 04:51:05Z ggregory $ + */ +public class SingletonIterator + implements ResettableIterator { + + /** Whether remove is allowed */ + private final boolean removeAllowed; + /** Is the cursor before the first element */ + private boolean beforeFirst = true; + /** Has the element been removed */ + private boolean removed = false; + /** The object */ + private E object; + + /** + * Constructs a new SingletonIterator where remove + * is a permitted operation. + * + * @param object the single object to return from the iterator + */ + public SingletonIterator(final E object) { + this(object, true); + } + + /** + * Constructs a new SingletonIterator optionally choosing if + * remove is a permitted operation. + * + * @param object the single object to return from the iterator + * @param removeAllowed true if remove is allowed + * @since 3.1 + */ + public SingletonIterator(final E object, final boolean removeAllowed) { + super(); + this.object = object; + this.removeAllowed = removeAllowed; + } + + //----------------------------------------------------------------------- + /** + * Is another object available from the iterator? + *

              + * This returns true if the single object hasn't been returned yet. + * + * @return true if the single object hasn't been returned yet + */ + public boolean hasNext() { + return beforeFirst && !removed; + } + + /** + * Get the next object from the iterator. + *

              + * This returns the single object if it hasn't been returned yet. + * + * @return the single object + * @throws NoSuchElementException if the single object has already + * been returned + */ + public E next() { + if (!beforeFirst || removed) { + throw new NoSuchElementException(); + } + beforeFirst = false; + return object; + } + + /** + * Remove the object from this iterator. + * + * @throws IllegalStateException if the {@code next} method has not + * yet been called, or the {@code remove} method has already + * been called after the last call to the {@code next} + * method. + * @throws UnsupportedOperationException if remove is not supported + */ + public void remove() { + if (removeAllowed) { + if (removed || beforeFirst) { + throw new IllegalStateException(); + } + object = null; + removed = true; + } else { + throw new UnsupportedOperationException(); + } + } + + /** + * Reset the iterator to the start. + */ + public void reset() { + beforeFirst = true; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/SingletonListIterator.java b/src/org/apache/commons/collections4/iterators/SingletonListIterator.java new file mode 100644 index 0000000..20f9b5a --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/SingletonListIterator.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.ResettableListIterator; + +/** + * SingletonIterator is an {@link ListIterator} over a single + * object instance. + * + * @since 2.1 + * @version $Id: SingletonListIterator.java 1612021 2014-07-20 04:51:05Z ggregory $ + */ +public class SingletonListIterator implements ResettableListIterator { + + private boolean beforeFirst = true; + private boolean nextCalled = false; + private boolean removed = false; + private E object; + + /** + * Constructs a new SingletonListIterator. + * + * @param object the single object to return from the iterator + */ + public SingletonListIterator(final E object) { + super(); + this.object = object; + } + + /** + * Is another object available from the iterator? + *

              + * This returns true if the single object hasn't been returned yet. + * + * @return true if the single object hasn't been returned yet + */ + public boolean hasNext() { + return beforeFirst && !removed; + } + + /** + * Is a previous object available from the iterator? + *

              + * This returns true if the single object has been returned. + * + * @return true if the single object has been returned + */ + public boolean hasPrevious() { + return !beforeFirst && !removed; + } + + /** + * Returns the index of the element that would be returned by a subsequent + * call to {@code next}. + * + * @return 0 or 1 depending on current state. + */ + public int nextIndex() { + return beforeFirst ? 0 : 1; + } + + /** + * Returns the index of the element that would be returned by a subsequent + * call to {@code previous}. A return value of -1 indicates that the iterator is currently at + * the start. + * + * @return 0 or -1 depending on current state. + */ + public int previousIndex() { + return beforeFirst ? -1 : 0; + } + + /** + * Get the next object from the iterator. + *

              + * This returns the single object if it hasn't been returned yet. + * + * @return the single object + * @throws NoSuchElementException if the single object has already + * been returned + */ + public E next() { + if (!beforeFirst || removed) { + throw new NoSuchElementException(); + } + beforeFirst = false; + nextCalled = true; + return object; + } + + /** + * Get the previous object from the iterator. + *

              + * This returns the single object if it has been returned. + * + * @return the single object + * @throws NoSuchElementException if the single object has not already + * been returned + */ + public E previous() { + if (beforeFirst || removed) { + throw new NoSuchElementException(); + } + beforeFirst = true; + return object; + } + + /** + * Remove the object from this iterator. + * @throws IllegalStateException if the {@code next} or {@code previous} + * method has not yet been called, or the {@code remove} method + * has already been called after the last call to {@code next} + * or {@code previous}. + */ + public void remove() { + if(!nextCalled || removed) { + throw new IllegalStateException(); + } + object = null; + removed = true; + } + + /** + * Add always throws {@link UnsupportedOperationException}. + * + * @param obj the object to add + * @throws UnsupportedOperationException always + */ + public void add(final E obj) { + throw new UnsupportedOperationException("add() is not supported by this iterator"); + } + + /** + * Set sets the value of the singleton. + * + * @param obj the object to set + * @throws IllegalStateException if {@code next} has not been called + * or the object has been removed + */ + public void set(final E obj) { + if (!nextCalled || removed) { + throw new IllegalStateException(); + } + this.object = obj; + } + + /** + * Reset the iterator back to the start. + */ + public void reset() { + beforeFirst = true; + nextCalled = false; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/SkippingIterator.java b/src/org/apache/commons/collections4/iterators/SkippingIterator.java new file mode 100644 index 0000000..bee201f --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/SkippingIterator.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +/** + * Decorates another iterator to skip the first N elements. + *

              + * In case an offset parameter other than 0 is provided, the decorated + * iterator is immediately advanced to this position, skipping all elements + * before that position. + * + * @since 4.1 + * @version $Id: SkippingIterator.java 1685902 2015-06-16 20:13:13Z tn $ + */ +public class SkippingIterator extends AbstractIteratorDecorator { + + /** The offset to bound the first element return */ + private final long offset; + + /** The position of the current element */ + private long pos; + + //----------------------------------------------------------------------- + + /** + * Decorates the specified iterator to skip all elements until the iterator + * reaches the position at {@code offset}. + *

              + * The iterator is immediately advanced until it reaches the position at {@code offset}, + * incurring O(n) time. + * + * @param iterator the iterator to be decorated + * @param offset the index of the first element of the decorated iterator to return + * @throws NullPointerException if iterator is null + * @throws IllegalArgumentException if offset is negative + */ + public SkippingIterator(final Iterator iterator, final long offset) { + super(iterator); + + if (offset < 0) { + throw new IllegalArgumentException("Offset parameter must not be negative."); + } + + this.offset = offset; + this.pos = 0; + init(); + } + + /** + * Skips the given number of elements. + */ + private void init() { + while (pos < offset && hasNext()) { + next(); + } + } + + //----------------------------------------------------------------------- + + @Override + public E next() { + final E next = super.next(); + pos++; + return next; + } + + /** + * {@inheritDoc} + *

              + * In case an offset other than 0 was specified, the underlying iterator will be advanced + * to this position upon creation. A call to {@link #remove()} will still result in an + * {@link IllegalStateException} if no explicit call to {@link #next()} has been made prior + * to calling {@link #remove()}. + */ + @Override + public void remove() { + if (pos <= offset) { + throw new IllegalStateException("remove() can not be called before calling next()"); + } + super.remove(); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/TransformIterator.java b/src/org/apache/commons/collections4/iterators/TransformIterator.java new file mode 100644 index 0000000..554bab6 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/TransformIterator.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +import org.apache.commons.collections4.Transformer; + +/** + * Decorates an iterator such that each element returned is transformed. + * + * @since 1.0 + * @version $Id: TransformIterator.java 1477802 2013-04-30 20:01:28Z tn $ + */ +public class TransformIterator implements Iterator { + + /** The iterator being used */ + private Iterator iterator; + /** The transformer being used */ + private Transformer transformer; + + //----------------------------------------------------------------------- + /** + * Constructs a new TransformIterator that will not function + * until the {@link #setIterator(Iterator) setIterator} and + * {@link #setTransformer(Transformer)} methods are invoked. + */ + public TransformIterator() { + super(); + } + + /** + * Constructs a new TransformIterator that won't transform + * elements from the given iterator. + * + * @param iterator the iterator to use + */ + public TransformIterator(final Iterator iterator) { + super(); + this.iterator = iterator; + } + + /** + * Constructs a new TransformIterator that will use the + * given iterator and transformer. If the given transformer is null, + * then objects will not be transformed. + * + * @param iterator the iterator to use + * @param transformer the transformer to use + */ + public TransformIterator(final Iterator iterator, + final Transformer transformer) { + super(); + this.iterator = iterator; + this.transformer = transformer; + } + + //----------------------------------------------------------------------- + public boolean hasNext() { + return iterator.hasNext(); + } + + /** + * Gets the next object from the iteration, transforming it using the + * current transformer. If the transformer is null, no transformation + * occurs and the object from the iterator is returned directly. + * + * @return the next object + * @throws java.util.NoSuchElementException if there are no more elements + */ + public O next() { + return transform(iterator.next()); + } + + public void remove() { + iterator.remove(); + } + + //----------------------------------------------------------------------- + /** + * Gets the iterator this iterator is using. + * + * @return the iterator. + */ + public Iterator getIterator() { + return iterator; + } + + /** + * Sets the iterator for this iterator to use. + * If iteration has started, this effectively resets the iterator. + * + * @param iterator the iterator to use + */ + public void setIterator(final Iterator iterator) { + this.iterator = iterator; + } + + //----------------------------------------------------------------------- + /** + * Gets the transformer this iterator is using. + * + * @return the transformer. + */ + public Transformer getTransformer() { + return transformer; + } + + /** + * Sets the transformer this the iterator to use. + * A null transformer is a no-op transformer. + * + * @param transformer the transformer to use + */ + public void setTransformer(final Transformer transformer) { + this.transformer = transformer; + } + + //----------------------------------------------------------------------- + /** + * Transforms the given object using the transformer. + * If the transformer is null, the original object is returned as-is. + * + * @param source the object to transform + * @return the transformed object + */ + protected O transform(final I source) { + return transformer.transform(source); + } +} diff --git a/src/org/apache/commons/collections4/iterators/UniqueFilterIterator.java b/src/org/apache/commons/collections4/iterators/UniqueFilterIterator.java new file mode 100644 index 0000000..420e7ce --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/UniqueFilterIterator.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +import org.apache.commons.collections4.functors.UniquePredicate; + +/** + * A FilterIterator which only returns "unique" Objects. Internally, + * the Iterator maintains a Set of objects it has already encountered, + * and duplicate Objects are skipped. + * + * @since 2.1 + * @version $Id: UniqueFilterIterator.java 1479385 2013-05-05 20:31:06Z tn $ + */ +public class UniqueFilterIterator extends FilterIterator { + + //------------------------------------------------------------------------- + + /** + * Constructs a new UniqueFilterIterator. + * + * @param iterator the iterator to use + */ + public UniqueFilterIterator(final Iterator iterator) { + super(iterator, UniquePredicate.uniquePredicate()); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/UnmodifiableIterator.java b/src/org/apache/commons/collections4/iterators/UnmodifiableIterator.java new file mode 100644 index 0000000..50fede3 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/UnmodifiableIterator.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.Iterator; + +import org.apache.commons.collections4.Unmodifiable; + +/** + * Decorates an iterator such that it cannot be modified. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableIterator implements Iterator, Unmodifiable { + + /** The iterator being decorated */ + private final Iterator iterator; + + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator such that it cannot be modified. + *

              + * If the iterator is already unmodifiable it is returned directly. + * + * @param the element type + * @param iterator the iterator to decorate + * @return a new unmodifiable iterator + * @throws NullPointerException if the iterator is null + */ + public static Iterator unmodifiableIterator(final Iterator iterator) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null"); + } + if (iterator instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final Iterator tmpIterator = (Iterator) iterator; + return tmpIterator; + } + return new UnmodifiableIterator(iterator); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param iterator the iterator to decorate + */ + private UnmodifiableIterator(final Iterator iterator) { + super(); + this.iterator = iterator; + } + + //----------------------------------------------------------------------- + public boolean hasNext() { + return iterator.hasNext(); + } + + public E next() { + return iterator.next(); + } + + public void remove() { + throw new UnsupportedOperationException("remove() is not supported"); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/UnmodifiableListIterator.java b/src/org/apache/commons/collections4/iterators/UnmodifiableListIterator.java new file mode 100644 index 0000000..20cece1 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/UnmodifiableListIterator.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ListIterator; + +import org.apache.commons.collections4.Unmodifiable; + +/** + * Decorates a list iterator such that it cannot be modified. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableListIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableListIterator implements ListIterator, Unmodifiable { + + /** The iterator being decorated */ + private final ListIterator iterator; + + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator such that it cannot be modified. + * + * @param the element type + * @param iterator the iterator to decorate + * @return a new unmodifiable list iterator + * @throws NullPointerException if the iterator is null + */ + public static ListIterator umodifiableListIterator(final ListIterator iterator) { + if (iterator == null) { + throw new NullPointerException("ListIterator must not be null"); + } + if (iterator instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final ListIterator tmpIterator = (ListIterator) iterator; + return tmpIterator; + } + return new UnmodifiableListIterator(iterator); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param iterator the iterator to decorate + */ + private UnmodifiableListIterator(final ListIterator iterator) { + super(); + this.iterator = iterator; + } + + //----------------------------------------------------------------------- + public boolean hasNext() { + return iterator.hasNext(); + } + + public E next() { + return iterator.next(); + } + + public int nextIndex() { + return iterator.nextIndex(); + } + + public boolean hasPrevious() { + return iterator.hasPrevious(); + } + + public E previous() { + return iterator.previous(); + } + + public int previousIndex() { + return iterator.previousIndex(); + } + + public void remove() { + throw new UnsupportedOperationException("remove() is not supported"); + } + + public void set(final E obj) { + throw new UnsupportedOperationException("set() is not supported"); + } + + public void add(final E obj) { + throw new UnsupportedOperationException("add() is not supported"); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/UnmodifiableMapIterator.java b/src/org/apache/commons/collections4/iterators/UnmodifiableMapIterator.java new file mode 100644 index 0000000..80bc1a0 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/UnmodifiableMapIterator.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.Unmodifiable; + +/** + * Decorates a map iterator such that it cannot be modified. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableMapIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableMapIterator implements MapIterator, Unmodifiable { + + /** The iterator being decorated */ + private final MapIterator iterator; + + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator such that it cannot be modified. + * + * @param the key type + * @param the value type + * @param iterator the iterator to decorate + * @return a new unmodifiable map iterator + * @throws NullPointerException if the iterator is null + */ + public static MapIterator unmodifiableMapIterator( + final MapIterator iterator) { + if (iterator == null) { + throw new NullPointerException("MapIterator must not be null"); + } + if (iterator instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final MapIterator tmpIterator = (MapIterator) iterator; + return tmpIterator; + } + return new UnmodifiableMapIterator(iterator); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param iterator the iterator to decorate + */ + private UnmodifiableMapIterator(final MapIterator iterator) { + super(); + this.iterator = iterator; + } + + //----------------------------------------------------------------------- + public boolean hasNext() { + return iterator.hasNext(); + } + + public K next() { + return iterator.next(); + } + + public K getKey() { + return iterator.getKey(); + } + + public V getValue() { + return iterator.getValue(); + } + + public V setValue(final V value) { + throw new UnsupportedOperationException("setValue() is not supported"); + } + + public void remove() { + throw new UnsupportedOperationException("remove() is not supported"); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/UnmodifiableOrderedMapIterator.java b/src/org/apache/commons/collections4/iterators/UnmodifiableOrderedMapIterator.java new file mode 100644 index 0000000..d381d89 --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/UnmodifiableOrderedMapIterator.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.Unmodifiable; + +/** + * Decorates an ordered map iterator such that it cannot be modified. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableOrderedMapIterator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableOrderedMapIterator implements OrderedMapIterator, + Unmodifiable { + + /** The iterator being decorated */ + private final OrderedMapIterator iterator; + + //----------------------------------------------------------------------- + /** + * Decorates the specified iterator such that it cannot be modified. + * + * @param the key type + * @param the value type + * @param iterator the iterator to decorate + * @return a new unmodifiable ordered map iterator + * @throws NullPointerException if the iterator is null + */ + public static OrderedMapIterator unmodifiableOrderedMapIterator( + final OrderedMapIterator iterator) { + + if (iterator == null) { + throw new NullPointerException("OrderedMapIterator must not be null"); + } + if (iterator instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final OrderedMapIterator tmpIterator = (OrderedMapIterator) iterator; + return tmpIterator; + } + return new UnmodifiableOrderedMapIterator(iterator); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param iterator the iterator to decorate + */ + private UnmodifiableOrderedMapIterator(final OrderedMapIterator iterator) { + super(); + this.iterator = iterator; + } + + //----------------------------------------------------------------------- + public boolean hasNext() { + return iterator.hasNext(); + } + + public K next() { + return iterator.next(); + } + + public boolean hasPrevious() { + return iterator.hasPrevious(); + } + + public K previous() { + return iterator.previous(); + } + + public K getKey() { + return iterator.getKey(); + } + + public V getValue() { + return iterator.getValue(); + } + + public V setValue(final V value) { + throw new UnsupportedOperationException("setValue() is not supported"); + } + + public void remove() { + throw new UnsupportedOperationException("remove() is not supported"); + } + +} diff --git a/src/org/apache/commons/collections4/iterators/ZippingIterator.java b/src/org/apache/commons/collections4/iterators/ZippingIterator.java new file mode 100644 index 0000000..e9a260e --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/ZippingIterator.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.iterators; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.FluentIterable; + +/** + * Provides an interleaved iteration over the elements contained in a + * collection of Iterators. + *

              + * Given two {@link Iterator} instances {@code A} and {@code B}, the + * {@link #next} method on this iterator will switch between {@code A.next()} + * and {@code B.next()} until both iterators are exhausted. + * + * @since 4.1 + * @version $Id: ZippingIterator.java 1682196 2015-05-28 09:58:09Z tn $ + */ +public class ZippingIterator implements Iterator { + + /** The {@link Iterator}s to evaluate. */ + private final Iterator> iterators; + + /** The next iterator to use for next(). */ + private Iterator nextIterator = null; + + /** The last iterator which was used for next(). */ + private Iterator lastReturned = null; + + // Constructors + // ---------------------------------------------------------------------- + + /** + * Constructs a new ZippingIterator that will provide + * interleaved iteration over the two given iterators. + * + * @param a the first child iterator + * @param b the second child iterator + * @throws NullPointerException if either iterator is null + */ + @SuppressWarnings("unchecked") + public ZippingIterator(final Iterator a, final Iterator b) { + this(new Iterator[] {a, b}); + } + + /** + * Constructs a new ZippingIterator that will provide + * interleaved iteration over the three given iterators. + * + * @param a the first child iterator + * @param b the second child iterator + * @param c the third child iterator + * @throws NullPointerException if either iterator is null + */ + @SuppressWarnings("unchecked") + public ZippingIterator(final Iterator a, + final Iterator b, + final Iterator c) { + this(new Iterator[] {a, b, c}); + } + + /** + * Constructs a new ZippingIterator that will provide + * interleaved iteration of the specified iterators. + * + * @param iterators the array of iterators + * @throws NullPointerException if any iterator is null + */ + @SafeVarargs + public ZippingIterator(final Iterator... iterators) { + // create a mutable list to be able to remove exhausted iterators + final List> list = new ArrayList>(); + for (final Iterator iterator : iterators) { + if (iterator == null) { + throw new NullPointerException("Iterator must not be null."); + } + list.add(iterator); + } + this.iterators = FluentIterable.of(list).loop().iterator(); + } + + // Iterator Methods + // ------------------------------------------------------------------- + + /** + * Returns {@code true} if any child iterator has remaining elements. + * + * @return true if this iterator has remaining elements + */ + public boolean hasNext() { + // the next iterator has already been determined + // this might happen if hasNext() is called multiple + if (nextIterator != null) { + return true; + } + + while(iterators.hasNext()) { + final Iterator childIterator = iterators.next(); + if (childIterator.hasNext()) { + nextIterator = childIterator; + return true; + } else { + // iterator is exhausted, remove it + iterators.remove(); + } + } + return false; + } + + /** + * Returns the next element from a child iterator. + * + * @return the next interleaved element + * @throws NoSuchElementException if no child iterator has any more elements + */ + public E next() throws NoSuchElementException { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + final E val = nextIterator.next(); + lastReturned = nextIterator; + nextIterator = null; + return val; + } + + /** + * Removes the last returned element from the child iterator that produced it. + * + * @throws IllegalStateException if there is no last returned element, or if + * the last returned element has already been removed + */ + public void remove() { + if (lastReturned == null) { + throw new IllegalStateException("No value can be removed at present"); + } + lastReturned.remove(); + lastReturned = null; + } + +} diff --git a/src/org/apache/commons/collections4/iterators/package-info.java b/src/org/apache/commons/collections4/iterators/package-info.java new file mode 100644 index 0000000..fc5547e --- /dev/null +++ b/src/org/apache/commons/collections4/iterators/package-info.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the + * {@link java.util.Iterator Iterator} interface. + *

              + * You may also consider using + * {@link org.apache.commons.collections4.IteratorUtils IteratorUtils}, + * which is a single class that uses static methods to construct instances + * of the classes in this package. + * + * @version $Id: package-info.java 1477802 2013-04-30 20:01:28Z tn $ + */ +package org.apache.commons.collections4.iterators; diff --git a/src/org/apache/commons/collections4/keyvalue/AbstractKeyValue.java b/src/org/apache/commons/collections4/keyvalue/AbstractKeyValue.java new file mode 100644 index 0000000..e856626 --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/AbstractKeyValue.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import org.apache.commons.collections4.KeyValue; + +/** + * Abstract pair class to assist with creating KeyValue + * and {@link java.util.Map.Entry Map.Entry} implementations. + * + * @since 3.0 + * @version $Id: AbstractKeyValue.java 1477753 2013-04-30 18:24:24Z tn $ + */ +public abstract class AbstractKeyValue implements KeyValue { + + /** The key */ + private K key; + /** The value */ + private V value; + + /** + * Constructs a new pair with the specified key and given value. + * + * @param key the key for the entry, may be null + * @param value the value for the entry, may be null + */ + protected AbstractKeyValue(final K key, final V value) { + super(); + this.key = key; + this.value = value; + } + + /** + * Gets the key from the pair. + * + * @return the key + */ + public K getKey() { + return key; + } + + protected K setKey(K key) { + final K old = this.key; + this.key = key; + return old; + } + + /** + * Gets the value from the pair. + * + * @return the value + */ + public V getValue() { + return value; + } + + protected V setValue(V value) { + final V old = this.value; + this.value = value; + return old; + } + + /** + * Gets a debugging String view of the pair. + * + * @return a String view of the entry + */ + @Override + public String toString() { + return new StringBuilder() + .append(getKey()) + .append('=') + .append(getValue()) + .toString(); + } + +} diff --git a/src/org/apache/commons/collections4/keyvalue/AbstractMapEntry.java b/src/org/apache/commons/collections4/keyvalue/AbstractMapEntry.java new file mode 100644 index 0000000..e9d3d0f --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/AbstractMapEntry.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import java.util.Map; + +/** + * Abstract Pair class to assist with creating correct + * {@link java.util.Map.Entry Map.Entry} implementations. + * + * @since 3.0 + * @version $Id: AbstractMapEntry.java 1477753 2013-04-30 18:24:24Z tn $ + */ +public abstract class AbstractMapEntry extends AbstractKeyValue implements Map.Entry { + + /** + * Constructs a new entry with the given key and given value. + * + * @param key the key for the entry, may be null + * @param value the value for the entry, may be null + */ + protected AbstractMapEntry(final K key, final V value) { + super(key, value); + } + + // Map.Entry interface + //------------------------------------------------------------------------- + /** + * Sets the value stored in this Map.Entry. + *

              + * This Map.Entry is not connected to a Map, so only the + * local data is changed. + * + * @param value the new value + * @return the previous value + */ + @Override + public V setValue(final V value) { + return super.setValue(value); + } + + /** + * Compares this Map.Entry with another Map.Entry. + *

              + * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)} + * + * @param obj the object to compare to + * @return true if equal key and value + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry other = (Map.Entry) obj; + return + (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && + (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue())); + } + + /** + * Gets a hashCode compatible with the equals method. + *

              + * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()} + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return (getKey() == null ? 0 : getKey().hashCode()) ^ + (getValue() == null ? 0 : getValue().hashCode()); + } + +} diff --git a/src/org/apache/commons/collections4/keyvalue/AbstractMapEntryDecorator.java b/src/org/apache/commons/collections4/keyvalue/AbstractMapEntryDecorator.java new file mode 100644 index 0000000..8dc36d3 --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/AbstractMapEntryDecorator.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import java.util.Map; + +import org.apache.commons.collections4.KeyValue; + +/** + * Provides a base decorator that allows additional functionality to be + * added to a {@link java.util.Map.Entry Map.Entry}. + * + * @since 3.0 + * @version $Id: AbstractMapEntryDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractMapEntryDecorator implements Map.Entry, KeyValue { + + /** The Map.Entry to decorate */ + private final Map.Entry entry; + + /** + * Constructor that wraps (not copies). + * + * @param entry the Map.Entry to decorate, must not be null + * @throws NullPointerException if the collection is null + */ + public AbstractMapEntryDecorator(final Map.Entry entry) { + if (entry == null) { + throw new NullPointerException("Map Entry must not be null."); + } + this.entry = entry; + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + protected Map.Entry getMapEntry() { + return entry; + } + + //----------------------------------------------------------------------- + + public K getKey() { + return entry.getKey(); + } + + public V getValue() { + return entry.getValue(); + } + + public V setValue(final V object) { + return entry.setValue(object); + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + return entry.equals(object); + } + + @Override + public int hashCode() { + return entry.hashCode(); + } + + @Override + public String toString() { + return entry.toString(); + } + +} diff --git a/src/org/apache/commons/collections4/keyvalue/DefaultKeyValue.java b/src/org/apache/commons/collections4/keyvalue/DefaultKeyValue.java new file mode 100644 index 0000000..06054cc --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/DefaultKeyValue.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import java.util.Map; + +import org.apache.commons.collections4.KeyValue; + +/** + * A mutable KeyValue pair that does not implement + * {@link java.util.Map.Entry Map.Entry}. + *

              + * Note that a DefaultKeyValue instance may not contain + * itself as a key or value. + * + * @since 3.0 + * @version $Id: DefaultKeyValue.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public class DefaultKeyValue extends AbstractKeyValue { + + /** + * Constructs a new pair with a null key and null value. + */ + public DefaultKeyValue() { + super(null, null); + } + + /** + * Constructs a new pair with the specified key and given value. + * + * @param key the key for the entry, may be null + * @param value the value for the entry, may be null + */ + public DefaultKeyValue(final K key, final V value) { + super(key, value); + } + + /** + * Constructs a new pair from the specified KeyValue. + * + * @param pair the pair to copy, must not be null + * @throws NullPointerException if the entry is null + */ + public DefaultKeyValue(final KeyValue pair) { + super(pair.getKey(), pair.getValue()); + } + + /** + * Constructs a new pair from the specified Map.Entry. + * + * @param entry the entry to copy, must not be null + * @throws NullPointerException if the entry is null + */ + public DefaultKeyValue(final Map.Entry entry) { + super(entry.getKey(), entry.getValue()); + } + + //----------------------------------------------------------------------- + /** + * Sets the key. + * + * @param key the new key + * @return the old key + * @throws IllegalArgumentException if key is this object + */ + @Override + public K setKey(final K key) { + if (key == this) { + throw new IllegalArgumentException("DefaultKeyValue may not contain itself as a key."); + } + + return super.setKey(key); + } + + /** + * Sets the value. + * + * @return the old value of the value + * @param value the new value + * @throws IllegalArgumentException if value is this object + */ + @Override + public V setValue(final V value) { + if (value == this) { + throw new IllegalArgumentException("DefaultKeyValue may not contain itself as a value."); + } + + return super.setValue(value); + } + + //----------------------------------------------------------------------- + /** + * Returns a new Map.Entry object with key and value from this pair. + * + * @return a MapEntry instance + */ + public Map.Entry toMapEntry() { + return new DefaultMapEntry(this); + } + + //----------------------------------------------------------------------- + /** + * Compares this Map.Entry with another Map.Entry. + *

              + * Returns true if the compared object is also a DefaultKeyValue, + * and its key and value are equal to this object's key and value. + * + * @param obj the object to compare to + * @return true if equal key and value + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof DefaultKeyValue == false) { + return false; + } + + final DefaultKeyValue other = (DefaultKeyValue) obj; + return + (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && + (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue())); + } + + /** + * Gets a hashCode compatible with the equals method. + *

              + * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}, + * however subclasses may override this. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return (getKey() == null ? 0 : getKey().hashCode()) ^ + (getValue() == null ? 0 : getValue().hashCode()); + } + +} diff --git a/src/org/apache/commons/collections4/keyvalue/DefaultMapEntry.java b/src/org/apache/commons/collections4/keyvalue/DefaultMapEntry.java new file mode 100644 index 0000000..893fb5c --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/DefaultMapEntry.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import java.util.Map; + +import org.apache.commons.collections4.KeyValue; + +/** + * A restricted implementation of {@link java.util.Map.Entry Map.Entry} that prevents + * the {@link java.util.Map.Entry Map.Entry} contract from being broken. + * + * @since 3.0 + * @version $Id: DefaultMapEntry.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public final class DefaultMapEntry extends AbstractMapEntry { + + /** + * Constructs a new entry with the specified key and given value. + * + * @param key the key for the entry, may be null + * @param value the value for the entry, may be null + */ + public DefaultMapEntry(final K key, final V value) { + super(key, value); + } + + /** + * Constructs a new entry from the specified KeyValue. + * + * @param pair the pair to copy, must not be null + * @throws NullPointerException if the entry is null + */ + public DefaultMapEntry(final KeyValue pair) { + super(pair.getKey(), pair.getValue()); + } + + /** + * Constructs a new entry from the specified Map.Entry. + * + * @param entry the entry to copy, must not be null + * @throws NullPointerException if the entry is null + */ + public DefaultMapEntry(final Map.Entry entry) { + super(entry.getKey(), entry.getValue()); + } + +} diff --git a/src/org/apache/commons/collections4/keyvalue/MultiKey.java b/src/org/apache/commons/collections4/keyvalue/MultiKey.java new file mode 100644 index 0000000..7a0b294 --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/MultiKey.java @@ -0,0 +1,281 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * A MultiKey allows multiple map keys to be merged together. + *

              + * The purpose of this class is to avoid the need to write code to handle + * maps of maps. An example might be the need to look up a file name by + * key and locale. The typical solution might be nested maps. This class + * can be used instead by creating an instance passing in the key and locale. + *

              + * Example usage: + *

              + * // populate map with data mapping key+locale to localizedText
              + * Map map = new HashMap();
              + * MultiKey multiKey = new MultiKey(key, locale);
              + * map.put(multiKey, localizedText);
              + *
              + * // later retrieve the localized text
              + * MultiKey multiKey = new MultiKey(key, locale);
              + * String localizedText = (String) map.get(multiKey);
              + * 
              + * + * @since 3.0 + * @version $Id: MultiKey.java 1705620 2015-09-28 08:53:44Z tn $ + */ +public class MultiKey implements Serializable { + // This class could implement List, but that would confuse it's purpose + + /** Serialisation version */ + private static final long serialVersionUID = 4465448607415788805L; + + /** The individual keys */ + private final K[] keys; + /** The cached hashCode */ + private transient int hashCode; + + /** + * Constructor taking two keys. + *

              + * The keys should be immutable + * If they are not then they must not be changed after adding to the MultiKey. + * + * @param key1 the first key + * @param key2 the second key + */ + @SuppressWarnings("unchecked") + public MultiKey(final K key1, final K key2) { + this((K[]) new Object[] { key1, key2 }, false); + } + + /** + * Constructor taking three keys. + *

              + * The keys should be immutable + * If they are not then they must not be changed after adding to the MultiKey. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + */ + @SuppressWarnings("unchecked") + public MultiKey(final K key1, final K key2, final K key3) { + this((K[]) new Object[] {key1, key2, key3}, false); + } + + /** + * Constructor taking four keys. + *

              + * The keys should be immutable + * If they are not then they must not be changed after adding to the MultiKey. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + */ + @SuppressWarnings("unchecked") + public MultiKey(final K key1, final K key2, final K key3, final K key4) { + this((K[]) new Object[] {key1, key2, key3, key4}, false); + } + + /** + * Constructor taking five keys. + *

              + * The keys should be immutable + * If they are not then they must not be changed after adding to the MultiKey. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param key5 the fifth key + */ + @SuppressWarnings("unchecked") + public MultiKey(final K key1, final K key2, final K key3, final K key4, final K key5) { + this((K[]) new Object[] {key1, key2, key3, key4, key5}, false); + } + + /** + * Constructor taking an array of keys which is cloned. + *

              + * The keys should be immutable + * If they are not then they must not be changed after adding to the MultiKey. + *

              + * This is equivalent to new MultiKey(keys, true). + * + * @param keys the array of keys, not null + * @throws IllegalArgumentException if the key array is null + */ + public MultiKey(final K[] keys) { + this(keys, true); + } + + /** + * Constructor taking an array of keys, optionally choosing whether to clone. + *

              + * If the array is not cloned, then it must not be modified. + *

              + * This method is public for performance reasons only, to avoid a clone. + * The hashcode is calculated once here in this method. + * Therefore, changing the array passed in would not change the hashcode but + * would change the equals method, which is a bug. + *

              + * This is the only fully safe usage of this constructor, as the object array + * is never made available in a variable: + *

              +     * new MultiKey(new Object[] {...}, false);
              +     * 
              + *

              + * The keys should be immutable + * If they are not then they must not be changed after adding to the MultiKey. + * + * @param keys the array of keys, not null + * @param makeClone true to clone the array, false to assign it + * @throws IllegalArgumentException if the key array is null + * @since 3.1 + */ + public MultiKey(final K[] keys, final boolean makeClone) { + super(); + if (keys == null) { + throw new IllegalArgumentException("The array of keys must not be null"); + } + if (makeClone) { + this.keys = keys.clone(); + } else { + this.keys = keys; + } + + calculateHashCode(keys); + } + + //----------------------------------------------------------------------- + /** + * Gets a clone of the array of keys. + *

              + * The keys should be immutable + * If they are not then they must not be changed. + * + * @return the individual keys + */ + public K[] getKeys() { + return keys.clone(); + } + + /** + * Gets the key at the specified index. + *

              + * The key should be immutable. + * If it is not then it must not be changed. + * + * @param index the index to retrieve + * @return the key at the index + * @throws IndexOutOfBoundsException if the index is invalid + * @since 3.1 + */ + public K getKey(final int index) { + return keys[index]; + } + + /** + * Gets the size of the list of keys. + * + * @return the size of the list of keys + * @since 3.1 + */ + public int size() { + return keys.length; + } + + //----------------------------------------------------------------------- + /** + * Compares this object to another. + *

              + * To be equal, the other object must be a MultiKey with the + * same number of keys which are also equal. + * + * @param other the other object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object other) { + if (other == this) { + return true; + } + if (other instanceof MultiKey) { + final MultiKey otherMulti = (MultiKey) other; + return Arrays.equals(keys, otherMulti.keys); + } + return false; + } + + /** + * Gets the combined hash code that is computed from all the keys. + *

              + * This value is computed once and then cached, so elements should not + * change their hash codes once created (note that this is the same + * constraint that would be used if the individual keys elements were + * themselves {@link java.util.Map Map} keys. + * + * @return the hash code + */ + @Override + public int hashCode() { + return hashCode; + } + + /** + * Gets a debugging string version of the key. + * + * @return a debugging string + */ + @Override + public String toString() { + return "MultiKey" + Arrays.toString(keys); + } + + /** + * Calculate the hash code of the instance using the provided keys. + * @param keys the keys to calculate the hash code for + */ + private void calculateHashCode(final Object[] keys) + { + int total = 0; + for (final Object key : keys) { + if (key != null) { + total ^= key.hashCode(); + } + } + hashCode = total; + } + + /** + * Recalculate the hash code after deserialization. The hash code of some + * keys might have change (hash codes based on the system hash code are + * only stable for the same process). + * @return the instance with recalculated hash code + */ + protected Object readResolve() { + calculateHashCode(keys); + return this; + } +} diff --git a/src/org/apache/commons/collections4/keyvalue/TiedMapEntry.java b/src/org/apache/commons/collections4/keyvalue/TiedMapEntry.java new file mode 100644 index 0000000..cf2b012 --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/TiedMapEntry.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.KeyValue; + +/** + * A {@link java.util.Map.Entry Map.Entry} tied to a map underneath. + *

              + * This can be used to enable a map entry to make changes on the underlying + * map, however this will probably mess up any iterators. + * + * @since 3.0 + * @version $Id: TiedMapEntry.java 1477753 2013-04-30 18:24:24Z tn $ + */ +public class TiedMapEntry implements Map.Entry, KeyValue, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = -8453869361373831205L; + + /** The map underlying the entry/iterator */ + private final Map map; + + /** The key */ + private final K key; + + /** + * Constructs a new entry with the given Map and key. + * + * @param map the map + * @param key the key + */ + public TiedMapEntry(final Map map, final K key) { + super(); + this.map = map; + this.key = key; + } + + // Map.Entry interface + //------------------------------------------------------------------------- + /** + * Gets the key of this entry + * + * @return the key + */ + public K getKey() { + return key; + } + + /** + * Gets the value of this entry direct from the map. + * + * @return the value + */ + public V getValue() { + return map.get(key); + } + + /** + * Sets the value associated with the key direct onto the map. + * + * @param value the new value + * @return the old value + * @throws IllegalArgumentException if the value is set to this map entry + */ + public V setValue(final V value) { + if (value == this) { + throw new IllegalArgumentException("Cannot set value to this map entry"); + } + return map.put(key, value); + } + + /** + * Compares this Map.Entry with another Map.Entry. + *

              + * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)} + * + * @param obj the object to compare to + * @return true if equal key and value + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry other = (Map.Entry) obj; + final Object value = getValue(); + return + (key == null ? other.getKey() == null : key.equals(other.getKey())) && + (value == null ? other.getValue() == null : value.equals(other.getValue())); + } + + /** + * Gets a hashCode compatible with the equals method. + *

              + * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()} + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + final Object value = getValue(); + return (getKey() == null ? 0 : getKey().hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + /** + * Gets a string version of the entry. + * + * @return entry as a string + */ + @Override + public String toString() { + return getKey() + "=" + getValue(); + } + +} diff --git a/src/org/apache/commons/collections4/keyvalue/UnmodifiableMapEntry.java b/src/org/apache/commons/collections4/keyvalue/UnmodifiableMapEntry.java new file mode 100644 index 0000000..62850be --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/UnmodifiableMapEntry.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.keyvalue; + +import java.util.Map; + +import org.apache.commons.collections4.KeyValue; +import org.apache.commons.collections4.Unmodifiable; + +/** + * A {@link java.util.Map.Entry Map.Entry} that throws + * UnsupportedOperationException when setValue is called. + * + * @since 3.0 + * @version $Id: UnmodifiableMapEntry.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public final class UnmodifiableMapEntry extends AbstractMapEntry implements Unmodifiable { + + /** + * Constructs a new entry with the specified key and given value. + * + * @param key the key for the entry, may be null + * @param value the value for the entry, may be null + */ + public UnmodifiableMapEntry(final K key, final V value) { + super(key, value); + } + + /** + * Constructs a new entry from the specified KeyValue. + * + * @param pair the pair to copy, must not be null + * @throws NullPointerException if the entry is null + */ + public UnmodifiableMapEntry(final KeyValue pair) { + super(pair.getKey(), pair.getValue()); + } + + /** + * Constructs a new entry from the specified Map.Entry. + * + * @param entry the entry to copy, must not be null + * @throws NullPointerException if the entry is null + */ + public UnmodifiableMapEntry(final Map.Entry entry) { + super(entry.getKey(), entry.getValue()); + } + + /** + * Throws UnsupportedOperationException. + * + * @param value the new value + * @return the previous value + * @throws UnsupportedOperationException always + */ + @Override + public V setValue(final V value) { + throw new UnsupportedOperationException("setValue() is not supported"); + } + +} diff --git a/src/org/apache/commons/collections4/keyvalue/package-info.java b/src/org/apache/commons/collections4/keyvalue/package-info.java new file mode 100644 index 0000000..da013fb --- /dev/null +++ b/src/org/apache/commons/collections4/keyvalue/package-info.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of collection and map related key/value classes. + * These are usually used in maps, however they can be used as data holders in any collection. + *

              + * The following key/value designs are included: + *

                + *
              • Map Entry - various map entry implementations + *
              • KeyValue - a key and value pair, without map entry semantics + *
              • MultiKey - a holder of multiple keys tied together + *
              + * + * @version $Id: package-info.java 1469004 2013-04-17 17:37:03Z tn $ + */ +package org.apache.commons.collections4.keyvalue; diff --git a/src/org/apache/commons/collections4/list/AbstractLinkedList.java b/src/org/apache/commons/collections4/list/AbstractLinkedList.java new file mode 100644 index 0000000..65c6c3e --- /dev/null +++ b/src/org/apache/commons/collections4/list/AbstractLinkedList.java @@ -0,0 +1,1067 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Array; +import java.util.AbstractList; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.OrderedIterator; + +/** + * An abstract implementation of a linked list which provides numerous points for + * subclasses to override. + *

              + * Overridable methods are provided to change the storage node and to change how + * nodes are added to and removed. Hopefully, all you need for unusual subclasses + * is here. + * + * @since 3.0 + * @version $Id: AbstractLinkedList.java 1494296 2013-06-18 20:54:29Z tn $ + */ +public abstract class AbstractLinkedList implements List { + + /* + * Implementation notes: + * - a standard circular doubly-linked list + * - a marker node is stored to mark the start and the end of the list + * - node creation and removal always occurs through createNode() and + * removeNode(). + * - a modification count is kept, with the same semantics as + * {@link java.util.LinkedList}. + * - respects {@link AbstractList#modCount} + */ + + /** + * A {@link Node} which indicates the start and end of the list and does not + * hold a value. The value of next is the first item in the + * list. The value of of previous is the last item in the list. + */ + transient Node header; + + /** The size of the list */ + transient int size; + + /** Modification count for iterators */ + transient int modCount; + + /** + * Constructor that does nothing intended for deserialization. + *

              + * If this constructor is used by a serializable subclass then the init() + * method must be called. + */ + protected AbstractLinkedList() { + super(); + } + + /** + * Constructs a list copying data from the specified collection. + * + * @param coll the collection to copy + */ + protected AbstractLinkedList(final Collection coll) { + super(); + init(); + addAll(coll); + } + + /** + * The equivalent of a default constructor, broken out so it can be called + * by any constructor and by readObject. + * Subclasses which override this method should make sure they call super, + * so the list is initialised properly. + */ + protected void init() { + header = createHeaderNode(); + } + + //----------------------------------------------------------------------- + + public int size() { + return size; + } + + public boolean isEmpty() { + return size() == 0; + } + + public E get(final int index) { + final Node node = getNode(index, false); + return node.getValue(); + } + + //----------------------------------------------------------------------- + + public Iterator iterator() { + return listIterator(); + } + + public ListIterator listIterator() { + return new LinkedListIterator(this, 0); + } + + public ListIterator listIterator(final int fromIndex) { + return new LinkedListIterator(this, fromIndex); + } + + //----------------------------------------------------------------------- + + public int indexOf(final Object value) { + int i = 0; + for (Node node = header.next; node != header; node = node.next) { + if (isEqualValue(node.getValue(), value)) { + return i; + } + i++; + } + return -1; + } + + public int lastIndexOf(final Object value) { + int i = size - 1; + for (Node node = header.previous; node != header; node = node.previous) { + if (isEqualValue(node.getValue(), value)) { + return i; + } + i--; + } + return -1; + } + + public boolean contains(final Object value) { + return indexOf(value) != -1; + } + + public boolean containsAll(final Collection coll) { + for (final Object o : coll) { + if (!contains(o)) { + return false; + } + } + return true; + } + + //----------------------------------------------------------------------- + + public Object[] toArray() { + return toArray(new Object[size]); + } + + @SuppressWarnings("unchecked") + public T[] toArray(T[] array) { + // Extend the array if needed + if (array.length < size) { + final Class componentType = array.getClass().getComponentType(); + array = (T[]) Array.newInstance(componentType, size); + } + // Copy the values into the array + int i = 0; + for (Node node = header.next; node != header; node = node.next, i++) { + array[i] = (T) node.getValue(); + } + // Set the value after the last value to null + if (array.length > size) { + array[size] = null; + } + return array; + } + + /** + * Gets a sublist of the main list. + * + * @param fromIndexInclusive the index to start from + * @param toIndexExclusive the index to end at + * @return the new sublist + */ + public List subList(final int fromIndexInclusive, final int toIndexExclusive) { + return new LinkedSubList(this, fromIndexInclusive, toIndexExclusive); + } + + //----------------------------------------------------------------------- + + public boolean add(final E value) { + addLast(value); + return true; + } + + public void add(final int index, final E value) { + final Node node = getNode(index, true); + addNodeBefore(node, value); + } + + public boolean addAll(final Collection coll) { + return addAll(size, coll); + } + + public boolean addAll(final int index, final Collection coll) { + final Node node = getNode(index, true); + for (final E e : coll) { + addNodeBefore(node, e); + } + return true; + } + + //----------------------------------------------------------------------- + + public E remove(final int index) { + final Node node = getNode(index, false); + final E oldValue = node.getValue(); + removeNode(node); + return oldValue; + } + + public boolean remove(final Object value) { + for (Node node = header.next; node != header; node = node.next) { + if (isEqualValue(node.getValue(), value)) { + removeNode(node); + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + *

              + * This implementation iterates over the elements of this list, checking each element in + * turn to see if it's contained in coll. If it's contained, it's removed + * from this list. As a consequence, it is advised to use a collection type for + * coll that provides a fast (e.g. O(1)) implementation of + * {@link Collection#contains(Object)}. + */ + public boolean removeAll(final Collection coll) { + boolean modified = false; + final Iterator it = iterator(); + while (it.hasNext()) { + if (coll.contains(it.next())) { + it.remove(); + modified = true; + } + } + return modified; + } + + //----------------------------------------------------------------------- + + /** + * {@inheritDoc} + *

              + * This implementation iterates over the elements of this list, checking each element in + * turn to see if it's contained in coll. If it's not contained, it's removed + * from this list. As a consequence, it is advised to use a collection type for + * coll that provides a fast (e.g. O(1)) implementation of + * {@link Collection#contains(Object)}. + */ + public boolean retainAll(final Collection coll) { + boolean modified = false; + final Iterator it = iterator(); + while (it.hasNext()) { + if (coll.contains(it.next()) == false) { + it.remove(); + modified = true; + } + } + return modified; + } + + public E set(final int index, final E value) { + final Node node = getNode(index, false); + final E oldValue = node.getValue(); + updateNode(node, value); + return oldValue; + } + + public void clear() { + removeAllNodes(); + } + + //----------------------------------------------------------------------- + + public E getFirst() { + final Node node = header.next; + if (node == header) { + throw new NoSuchElementException(); + } + return node.getValue(); + } + + public E getLast() { + final Node node = header.previous; + if (node == header) { + throw new NoSuchElementException(); + } + return node.getValue(); + } + + public boolean addFirst(final E o) { + addNodeAfter(header, o); + return true; + } + + public boolean addLast(final E o) { + addNodeBefore(header, o); + return true; + } + + public E removeFirst() { + final Node node = header.next; + if (node == header) { + throw new NoSuchElementException(); + } + final E oldValue = node.getValue(); + removeNode(node); + return oldValue; + } + + public E removeLast() { + final Node node = header.previous; + if (node == header) { + throw new NoSuchElementException(); + } + final E oldValue = node.getValue(); + removeNode(node); + return oldValue; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof List == false) { + return false; + } + final List other = (List) obj; + if (other.size() != size()) { + return false; + } + final ListIterator it1 = listIterator(); + final ListIterator it2 = other.listIterator(); + while (it1.hasNext() && it2.hasNext()) { + final Object o1 = it1.next(); + final Object o2 = it2.next(); + if (!(o1 == null ? o2 == null : o1.equals(o2))) { + return false; + } + } + return !(it1.hasNext() || it2.hasNext()); + } + + @Override + public int hashCode() { + int hashCode = 1; + for (final E e : this) { + hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode()); + } + return hashCode; + } + + @Override + public String toString() { + if (size() == 0) { + return "[]"; + } + final StringBuilder buf = new StringBuilder(16 * size()); + buf.append('['); + + final Iterator it = iterator(); + boolean hasNext = it.hasNext(); + while (hasNext) { + final Object value = it.next(); + buf.append(value == this ? "(this Collection)" : value); + hasNext = it.hasNext(); + if (hasNext) { + buf.append(", "); + } + } + buf.append(']'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * Compares two values for equals. + * This implementation uses the equals method. + * Subclasses can override this to match differently. + * + * @param value1 the first value to compare, may be null + * @param value2 the second value to compare, may be null + * @return true if equal + */ + protected boolean isEqualValue(final Object value1, final Object value2) { + return value1 == value2 || (value1 == null ? false : value1.equals(value2)); + } + + /** + * Updates the node with a new value. + * This implementation sets the value on the node. + * Subclasses can override this to record the change. + * + * @param node node to update + * @param value new value of the node + */ + protected void updateNode(final Node node, final E value) { + node.setValue(value); + } + + /** + * Creates a new node with previous, next and element all set to null. + * This implementation creates a new empty Node. + * Subclasses can override this to create a different class. + * + * @return newly created node + */ + protected Node createHeaderNode() { + return new Node(); + } + + /** + * Creates a new node with the specified properties. + * This implementation creates a new Node with data. + * Subclasses can override this to create a different class. + * + * @param value value of the new node + * @return a new node containing the value + */ + protected Node createNode(final E value) { + return new Node(value); + } + + /** + * Creates a new node with the specified object as its + * value and inserts it before node. + *

              + * This implementation uses {@link #createNode(Object)} and + * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}. + * + * @param node node to insert before + * @param value value of the newly added node + * @throws NullPointerException if node is null + */ + protected void addNodeBefore(final Node node, final E value) { + final Node newNode = createNode(value); + addNode(newNode, node); + } + + /** + * Creates a new node with the specified object as its + * value and inserts it after node. + *

              + * This implementation uses {@link #createNode(Object)} and + * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}. + * + * @param node node to insert after + * @param value value of the newly added node + * @throws NullPointerException if node is null + */ + protected void addNodeAfter(final Node node, final E value) { + final Node newNode = createNode(value); + addNode(newNode, node.next); + } + + /** + * Inserts a new node into the list. + * + * @param nodeToInsert new node to insert + * @param insertBeforeNode node to insert before + * @throws NullPointerException if either node is null + */ + protected void addNode(final Node nodeToInsert, final Node insertBeforeNode) { + nodeToInsert.next = insertBeforeNode; + nodeToInsert.previous = insertBeforeNode.previous; + insertBeforeNode.previous.next = nodeToInsert; + insertBeforeNode.previous = nodeToInsert; + size++; + modCount++; + } + + /** + * Removes the specified node from the list. + * + * @param node the node to remove + * @throws NullPointerException if node is null + */ + protected void removeNode(final Node node) { + node.previous.next = node.next; + node.next.previous = node.previous; + size--; + modCount++; + } + + /** + * Removes all nodes by resetting the circular list marker. + */ + protected void removeAllNodes() { + header.next = header; + header.previous = header; + size = 0; + modCount++; + } + + /** + * Gets the node at a particular index. + * + * @param index the index, starting from 0 + * @param endMarkerAllowed whether or not the end marker can be returned if + * startIndex is set to the list's size + * @return the node at the given index + * @throws IndexOutOfBoundsException if the index is less than 0; equal to + * the size of the list and endMakerAllowed is false; or greater than the + * size of the list + */ + protected Node getNode(final int index, final boolean endMarkerAllowed) throws IndexOutOfBoundsException { + // Check the index is within the bounds + if (index < 0) { + throw new IndexOutOfBoundsException("Couldn't get the node: " + + "index (" + index + ") less than zero."); + } + if (!endMarkerAllowed && index == size) { + throw new IndexOutOfBoundsException("Couldn't get the node: " + + "index (" + index + ") is the size of the list."); + } + if (index > size) { + throw new IndexOutOfBoundsException("Couldn't get the node: " + + "index (" + index + ") greater than the size of the " + + "list (" + size + ")."); + } + // Search the list and get the node + Node node; + if (index < size / 2) { + // Search forwards + node = header.next; + for (int currentIndex = 0; currentIndex < index; currentIndex++) { + node = node.next; + } + } else { + // Search backwards + node = header; + for (int currentIndex = size; currentIndex > index; currentIndex--) { + node = node.previous; + } + } + return node; + } + + //----------------------------------------------------------------------- + /** + * Creates an iterator for the sublist. + * + * @param subList the sublist to get an iterator for + * @return a new iterator on the given sublist + */ + protected Iterator createSubListIterator(final LinkedSubList subList) { + return createSubListListIterator(subList, 0); + } + + /** + * Creates a list iterator for the sublist. + * + * @param subList the sublist to get an iterator for + * @param fromIndex the index to start from, relative to the sublist + * @return a new list iterator on the given sublist + */ + protected ListIterator createSubListListIterator(final LinkedSubList subList, final int fromIndex) { + return new LinkedSubListIterator(subList, fromIndex); + } + + //----------------------------------------------------------------------- + /** + * Serializes the data held in this object to the stream specified. + *

              + * The first serializable subclass must call this method from + * writeObject. + * + * @param outputStream the stream to write the object to + * @throws IOException if anything goes wrong + */ + protected void doWriteObject(final ObjectOutputStream outputStream) throws IOException { + // Write the size so we know how many nodes to read back + outputStream.writeInt(size()); + for (final E e : this) { + outputStream.writeObject(e); + } + } + + /** + * Deserializes the data held in this object to the stream specified. + *

              + * The first serializable subclass must call this method from + * readObject. + * + * @param inputStream the stream to read the object from + * @throws IOException if any error occurs while reading from the stream + * @throws ClassNotFoundException if a class read from the stream can not be loaded + */ + @SuppressWarnings("unchecked") + protected void doReadObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException { + init(); + final int size = inputStream.readInt(); + for (int i = 0; i < size; i++) { + add((E) inputStream.readObject()); + } + } + + //----------------------------------------------------------------------- + /** + * A node within the linked list. + *

              + * From Commons Collections 3.1, all access to the value property + * is via the methods on this class. + */ + protected static class Node { + + /** A pointer to the node before this node */ + protected Node previous; + /** A pointer to the node after this node */ + protected Node next; + /** The object contained within this node */ + protected E value; + + /** + * Constructs a new header node. + */ + protected Node() { + super(); + previous = this; + next = this; + } + + /** + * Constructs a new node. + * + * @param value the value to store + */ + protected Node(final E value) { + super(); + this.value = value; + } + + /** + * Constructs a new node. + * + * @param previous the previous node in the list + * @param next the next node in the list + * @param value the value to store + */ + protected Node(final Node previous, final Node next, final E value) { + super(); + this.previous = previous; + this.next = next; + this.value = value; + } + + /** + * Gets the value of the node. + * + * @return the value + * @since 3.1 + */ + protected E getValue() { + return value; + } + + /** + * Sets the value of the node. + * + * @param value the value + * @since 3.1 + */ + protected void setValue(final E value) { + this.value = value; + } + + /** + * Gets the previous node. + * + * @return the previous node + * @since 3.1 + */ + protected Node getPreviousNode() { + return previous; + } + + /** + * Sets the previous node. + * + * @param previous the previous node + * @since 3.1 + */ + protected void setPreviousNode(final Node previous) { + this.previous = previous; + } + + /** + * Gets the next node. + * + * @return the next node + * @since 3.1 + */ + protected Node getNextNode() { + return next; + } + + /** + * Sets the next node. + * + * @param next the next node + * @since 3.1 + */ + protected void setNextNode(final Node next) { + this.next = next; + } + } + + //----------------------------------------------------------------------- + /** + * A list iterator over the linked list. + */ + protected static class LinkedListIterator implements ListIterator, OrderedIterator { + + /** The parent list */ + protected final AbstractLinkedList parent; + + /** + * The node that will be returned by {@link #next()}. If this is equal + * to {@link AbstractLinkedList#header} then there are no more values to return. + */ + protected Node next; + + /** + * The index of {@link #next}. + */ + protected int nextIndex; + + /** + * The last node that was returned by {@link #next()} or {@link + * #previous()}. Set to null if {@link #next()} or {@link + * #previous()} haven't been called, or if the node has been removed + * with {@link #remove()} or a new node added with {@link #add(Object)}. + * Should be accessed through {@link #getLastNodeReturned()} to enforce + * this behaviour. + */ + protected Node current; + + /** + * The modification count that the list is expected to have. If the list + * doesn't have this count, then a + * {@link java.util.ConcurrentModificationException} may be thrown by + * the operations. + */ + protected int expectedModCount; + + /** + * Create a ListIterator for a list. + * + * @param parent the parent list + * @param fromIndex the index to start at + * @throws IndexOutOfBoundsException if fromIndex is less than 0 or greater than the size of the list + */ + protected LinkedListIterator(final AbstractLinkedList parent, final int fromIndex) + throws IndexOutOfBoundsException { + super(); + this.parent = parent; + this.expectedModCount = parent.modCount; + this.next = parent.getNode(fromIndex, true); + this.nextIndex = fromIndex; + } + + /** + * Checks the modification count of the list is the value that this + * object expects. + * + * @throws ConcurrentModificationException If the list's modification + * count isn't the value that was expected. + */ + protected void checkModCount() { + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + + /** + * Gets the last node returned. + * + * @return the last node returned + * @throws IllegalStateException If {@link #next()} or {@link #previous()} haven't been called, + * or if the node has been removed with {@link #remove()} or a new node added with {@link #add(Object)}. + */ + protected Node getLastNodeReturned() throws IllegalStateException { + if (current == null) { + throw new IllegalStateException(); + } + return current; + } + + public boolean hasNext() { + return next != parent.header; + } + + public E next() { + checkModCount(); + if (!hasNext()) { + throw new NoSuchElementException("No element at index " + nextIndex + "."); + } + final E value = next.getValue(); + current = next; + next = next.next; + nextIndex++; + return value; + } + + public boolean hasPrevious() { + return next.previous != parent.header; + } + + public E previous() { + checkModCount(); + if (!hasPrevious()) { + throw new NoSuchElementException("Already at start of list."); + } + next = next.previous; + final E value = next.getValue(); + current = next; + nextIndex--; + return value; + } + + public int nextIndex() { + return nextIndex; + } + + public int previousIndex() { + // not normally overridden, as relative to nextIndex() + return nextIndex() - 1; + } + + public void remove() { + checkModCount(); + if (current == next) { + // remove() following previous() + next = next.next; + parent.removeNode(getLastNodeReturned()); + } else { + // remove() following next() + parent.removeNode(getLastNodeReturned()); + nextIndex--; + } + current = null; + expectedModCount++; + } + + public void set(final E obj) { + checkModCount(); + getLastNodeReturned().setValue(obj); + } + + public void add(final E obj) { + checkModCount(); + parent.addNodeBefore(next, obj); + current = null; + nextIndex++; + expectedModCount++; + } + + } + + //----------------------------------------------------------------------- + /** + * A list iterator over the linked sub list. + */ + protected static class LinkedSubListIterator extends LinkedListIterator { + + /** The parent list */ + protected final LinkedSubList sub; + + protected LinkedSubListIterator(final LinkedSubList sub, final int startIndex) { + super(sub.parent, startIndex + sub.offset); + this.sub = sub; + } + + @Override + public boolean hasNext() { + return nextIndex() < sub.size; + } + + @Override + public boolean hasPrevious() { + return previousIndex() >= 0; + } + + @Override + public int nextIndex() { + return super.nextIndex() - sub.offset; + } + + @Override + public void add(final E obj) { + super.add(obj); + sub.expectedModCount = parent.modCount; + sub.size++; + } + + @Override + public void remove() { + super.remove(); + sub.expectedModCount = parent.modCount; + sub.size--; + } + } + + //----------------------------------------------------------------------- + /** + * The sublist implementation for AbstractLinkedList. + */ + protected static class LinkedSubList extends AbstractList { + /** The main list */ + AbstractLinkedList parent; + /** Offset from the main list */ + int offset; + /** Sublist size */ + int size; + /** Sublist modCount */ + int expectedModCount; + + protected LinkedSubList(final AbstractLinkedList parent, final int fromIndex, final int toIndex) { + if (fromIndex < 0) { + throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); + } + if (toIndex > parent.size()) { + throw new IndexOutOfBoundsException("toIndex = " + toIndex); + } + if (fromIndex > toIndex) { + throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + this.parent = parent; + this.offset = fromIndex; + this.size = toIndex - fromIndex; + this.expectedModCount = parent.modCount; + } + + @Override + public int size() { + checkModCount(); + return size; + } + + @Override + public E get(final int index) { + rangeCheck(index, size); + checkModCount(); + return parent.get(index + offset); + } + + @Override + public void add(final int index, final E obj) { + rangeCheck(index, size + 1); + checkModCount(); + parent.add(index + offset, obj); + expectedModCount = parent.modCount; + size++; + LinkedSubList.this.modCount++; + } + + @Override + public E remove(final int index) { + rangeCheck(index, size); + checkModCount(); + final E result = parent.remove(index + offset); + expectedModCount = parent.modCount; + size--; + LinkedSubList.this.modCount++; + return result; + } + + @Override + public boolean addAll(final Collection coll) { + return addAll(size, coll); + } + + @Override + public boolean addAll(final int index, final Collection coll) { + rangeCheck(index, size + 1); + final int cSize = coll.size(); + if (cSize == 0) { + return false; + } + + checkModCount(); + parent.addAll(offset + index, coll); + expectedModCount = parent.modCount; + size += cSize; + LinkedSubList.this.modCount++; + return true; + } + + @Override + public E set(final int index, final E obj) { + rangeCheck(index, size); + checkModCount(); + return parent.set(index + offset, obj); + } + + @Override + public void clear() { + checkModCount(); + final Iterator it = iterator(); + while (it.hasNext()) { + it.next(); + it.remove(); + } + } + + @Override + public Iterator iterator() { + checkModCount(); + return parent.createSubListIterator(this); + } + + @Override + public ListIterator listIterator(final int index) { + rangeCheck(index, size + 1); + checkModCount(); + return parent.createSubListListIterator(this, index); + } + + @Override + public List subList(final int fromIndexInclusive, final int toIndexExclusive) { + return new LinkedSubList(parent, fromIndexInclusive + offset, toIndexExclusive + offset); + } + + protected void rangeCheck(final int index, final int beyond) { + if (index < 0 || index >= beyond) { + throw new IndexOutOfBoundsException("Index '" + index + "' out of bounds for size '" + size + "'"); + } + } + + protected void checkModCount() { + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + } + +} diff --git a/src/org/apache/commons/collections4/list/AbstractListDecorator.java b/src/org/apache/commons/collections4/list/AbstractListDecorator.java new file mode 100644 index 0000000..45738ba --- /dev/null +++ b/src/org/apache/commons/collections4/list/AbstractListDecorator.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.Collection; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.collections4.collection.AbstractCollectionDecorator; + +/** + * Decorates another {@link List} to provide additional behaviour. + *

              + * Methods are forwarded directly to the decorated list. + * + * @param the type of the elements in the list + * @since 3.0 + * @version $Id: AbstractListDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractListDecorator extends AbstractCollectionDecorator + implements List { + + /** Serialization version--necessary in an abstract class? */ + private static final long serialVersionUID = 4500739654952315623L; + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractListDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param list the list to decorate, must not be null + * @throws NullPointerException if list is null + */ + protected AbstractListDecorator(final List list) { + super(list); + } + + /** + * Gets the list being decorated. + * + * @return the decorated list + */ + @Override + protected List decorated() { + return (List) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + public void add(final int index, final E object) { + decorated().add(index, object); + } + + public boolean addAll(final int index, final Collection coll) { + return decorated().addAll(index, coll); + } + + public E get(final int index) { + return decorated().get(index); + } + + public int indexOf(final Object object) { + return decorated().indexOf(object); + } + + public int lastIndexOf(final Object object) { + return decorated().lastIndexOf(object); + } + + public ListIterator listIterator() { + return decorated().listIterator(); + } + + public ListIterator listIterator(final int index) { + return decorated().listIterator(index); + } + + public E remove(final int index) { + return decorated().remove(index); + } + + public E set(final int index, final E object) { + return decorated().set(index, object); + } + + public List subList(final int fromIndex, final int toIndex) { + return decorated().subList(fromIndex, toIndex); + } + +} diff --git a/src/org/apache/commons/collections4/list/AbstractSerializableListDecorator.java b/src/org/apache/commons/collections4/list/AbstractSerializableListDecorator.java new file mode 100644 index 0000000..0b6c539 --- /dev/null +++ b/src/org/apache/commons/collections4/list/AbstractSerializableListDecorator.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.List; + +/** + * Serializable subclass of AbstractListDecorator. + * + * @since 3.1 + * @version $Id: AbstractSerializableListDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractSerializableListDecorator + extends AbstractListDecorator { + + /** Serialization version */ + private static final long serialVersionUID = 2684959196747496299L; + + /** + * Constructor that wraps (not copies). + * + * @param list the list to decorate, must not be null + * @throws NullPointerException if list is null + */ + protected AbstractSerializableListDecorator(final List list) { + super(list); + } + + //----------------------------------------------------------------------- + /** + * Write the list out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the list in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + +} diff --git a/src/org/apache/commons/collections4/list/CursorableLinkedList.java b/src/org/apache/commons/collections4/list/CursorableLinkedList.java new file mode 100644 index 0000000..3b21ce4 --- /dev/null +++ b/src/org/apache/commons/collections4/list/CursorableLinkedList.java @@ -0,0 +1,620 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +/** + * A List implementation with a ListIterator that + * allows concurrent modifications to the underlying list. + *

              + * This implementation supports all of the optional {@link List} operations. + * It extends AbstractLinkedList and thus provides the + * stack/queue/dequeue operations available in {@link java.util.LinkedList}. + *

              + * The main feature of this class is the ability to modify the list and the + * iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()} + * methods provides access to a Cursor instance which extends + * ListIterator. The cursor allows changes to the list concurrent + * with changes to the iterator. Note that the {@link #iterator()} method and + * sublists do not provide this cursor behaviour. + *

              + * The Cursor class is provided partly for backwards compatibility + * and partly because it allows the cursor to be directly closed. Closing the + * cursor is optional because references are held via a WeakReference. + * For most purposes, simply modify the iterator and list at will, and then let + * the garbage collector to the rest. + *

              + * Note that this implementation is not synchronized. + * + * @see java.util.LinkedList + * @since 1.0 + * @version $Id: CursorableLinkedList.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public class CursorableLinkedList extends AbstractLinkedList implements Serializable { + + /** Ensure serialization compatibility */ + private static final long serialVersionUID = 8836393098519411393L; + + /** A list of the cursor currently open on this list */ + private transient List>> cursors; + + //----------------------------------------------------------------------- + /** + * Constructor that creates. + */ + public CursorableLinkedList() { + super(); + init(); // must call init() as use super(); + } + + /** + * Constructor that copies the specified collection + * + * @param coll the collection to copy + */ + public CursorableLinkedList(final Collection coll) { + super(coll); + } + + /** + * The equivalent of a default constructor called + * by any constructor and by readObject. + */ + @Override + protected void init() { + super.init(); + cursors = new ArrayList>>(); + } + + //----------------------------------------------------------------------- + /** + * Returns an iterator that does not support concurrent modification. + *

              + * If the underlying list is modified while iterating using this iterator + * a ConcurrentModificationException will occur. + * The cursor behaviour is available via {@link #listIterator()}. + * + * @return a new iterator that does not support concurrent modification + */ + @Override + public Iterator iterator() { + return super.listIterator(0); + } + + /** + * Returns a cursor iterator that allows changes to the underlying list in parallel. + *

              + * The cursor enables iteration and list changes to occur in any order without + * invalidating the iterator (from one thread). When elements are added to the + * list, an event is fired to all active cursors enabling them to adjust to the + * change in the list. + *

              + * When the "current" (i.e., last returned by {@link ListIterator#next} + * or {@link ListIterator#previous}) element of the list is removed, + * the cursor automatically adjusts to the change (invalidating the + * last returned value such that it cannot be removed). + * + * @return a new cursor iterator + */ + @Override + public ListIterator listIterator() { + return cursor(0); + } + + /** + * Returns a cursor iterator that allows changes to the underlying list in parallel. + *

              + * The cursor enables iteration and list changes to occur in any order without + * invalidating the iterator (from one thread). When elements are added to the + * list, an event is fired to all active cursors enabling them to adjust to the + * change in the list. + *

              + * When the "current" (i.e., last returned by {@link ListIterator#next} + * or {@link ListIterator#previous}) element of the list is removed, + * the cursor automatically adjusts to the change (invalidating the + * last returned value such that it cannot be removed). + * + * @param fromIndex the index to start from + * @return a new cursor iterator + */ + @Override + public ListIterator listIterator(final int fromIndex) { + return cursor(fromIndex); + } + + /** + * Returns a {@link Cursor} for iterating through the elements of this list. + *

              + * A Cursor is a ListIterator with an additional + * close() method. Calling this method immediately discards the + * references to the cursor. If it is not called, then the garbage collector + * will still remove the reference as it is held via a WeakReference. + *

              + * The cursor enables iteration and list changes to occur in any order without + * invalidating the iterator (from one thread). When elements are added to the + * list, an event is fired to all active cursors enabling them to adjust to the + * change in the list. + *

              + * When the "current" (i.e., last returned by {@link ListIterator#next} + * or {@link ListIterator#previous}) element of the list is removed, + * the cursor automatically adjusts to the change (invalidating the + * last returned value such that it cannot be removed). + *

              + * The {@link #listIterator()} method returns the same as this method, and can + * be cast to a Cursor if the close method is required. + * + * @return a new cursor iterator + */ + public CursorableLinkedList.Cursor cursor() { + return cursor(0); + } + + /** + * Returns a {@link Cursor} for iterating through the elements of this list + * starting from a specified index. + *

              + * A Cursor is a ListIterator with an additional + * close() method. Calling this method immediately discards the + * references to the cursor. If it is not called, then the garbage collector + * will still remove the reference as it is held via a WeakReference. + *

              + * The cursor enables iteration and list changes to occur in any order without + * invalidating the iterator (from one thread). When elements are added to the + * list, an event is fired to all active cursors enabling them to adjust to the + * change in the list. + *

              + * When the "current" (i.e., last returned by {@link ListIterator#next} + * or {@link ListIterator#previous}) element of the list is removed, + * the cursor automatically adjusts to the change (invalidating the + * last returned value such that it cannot be removed). + *

              + * The {@link #listIterator(int)} method returns the same as this method, and can + * be cast to a Cursor if the close method is required. + * + * @param fromIndex the index to start from + * @return a new cursor iterator + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > size()). + */ + public CursorableLinkedList.Cursor cursor(final int fromIndex) { + final Cursor cursor = new Cursor(this, fromIndex); + registerCursor(cursor); + return cursor; + } + + //----------------------------------------------------------------------- + /** + * Updates the node with a new value. + * This implementation sets the value on the node. + * Subclasses can override this to record the change. + * + * @param node node to update + * @param value new value of the node + */ + @Override + protected void updateNode(final Node node, final E value) { + super.updateNode(node, value); + broadcastNodeChanged(node); + } + + /** + * Inserts a new node into the list. + * + * @param nodeToInsert new node to insert + * @param insertBeforeNode node to insert before + * @throws NullPointerException if either node is null + */ + @Override + protected void addNode(final Node nodeToInsert, final Node insertBeforeNode) { + super.addNode(nodeToInsert, insertBeforeNode); + broadcastNodeInserted(nodeToInsert); + } + + /** + * Removes the specified node from the list. + * + * @param node the node to remove + * @throws NullPointerException if node is null + */ + @Override + protected void removeNode(final Node node) { + super.removeNode(node); + broadcastNodeRemoved(node); + } + + /** + * Removes all nodes by iteration. + */ + @Override + protected void removeAllNodes() { + if (size() > 0) { + // superclass implementation would break all the iterators + final Iterator it = iterator(); + while (it.hasNext()) { + it.next(); + it.remove(); + } + } + } + + //----------------------------------------------------------------------- + /** + * Registers a cursor to be notified of changes to this list. + * + * @param cursor the cursor to register + */ + protected void registerCursor(final Cursor cursor) { + // We take this opportunity to clean the cursors list + // of WeakReference objects to garbage-collected cursors. + for (final Iterator>> it = cursors.iterator(); it.hasNext();) { + final WeakReference> ref = it.next(); + if (ref.get() == null) { + it.remove(); + } + } + cursors.add(new WeakReference>(cursor)); + } + + /** + * Deregisters a cursor from the list to be notified of changes. + * + * @param cursor the cursor to deregister + */ + protected void unregisterCursor(final Cursor cursor) { + for (final Iterator>> it = cursors.iterator(); it.hasNext();) { + final WeakReference> ref = it.next(); + final Cursor cur = ref.get(); + if (cur == null) { + // some other unrelated cursor object has been + // garbage-collected; let's take the opportunity to + // clean up the cursors list anyway.. + it.remove(); + } else if (cur == cursor) { + ref.clear(); + it.remove(); + break; + } + } + } + + //----------------------------------------------------------------------- + /** + * Informs all of my registered cursors that the specified + * element was changed. + * + * @param node the node that was changed + */ + protected void broadcastNodeChanged(final Node node) { + final Iterator>> it = cursors.iterator(); + while (it.hasNext()) { + final WeakReference> ref = it.next(); + final Cursor cursor = ref.get(); + if (cursor == null) { + it.remove(); // clean up list + } else { + cursor.nodeChanged(node); + } + } + } + + /** + * Informs all of my registered cursors that the specified + * element was just removed from my list. + * + * @param node the node that was changed + */ + protected void broadcastNodeRemoved(final Node node) { + final Iterator>> it = cursors.iterator(); + while (it.hasNext()) { + final WeakReference> ref = it.next(); + final Cursor cursor = ref.get(); + if (cursor == null) { + it.remove(); // clean up list + } else { + cursor.nodeRemoved(node); + } + } + } + + /** + * Informs all of my registered cursors that the specified + * element was just added to my list. + * + * @param node the node that was changed + */ + protected void broadcastNodeInserted(final Node node) { + final Iterator>> it = cursors.iterator(); + while (it.hasNext()) { + final WeakReference> ref = it.next(); + final Cursor cursor = ref.get(); + if (cursor == null) { + it.remove(); // clean up list + } else { + cursor.nodeInserted(node); + } + } + } + + //----------------------------------------------------------------------- + /** + * Serializes the data held in this object to the stream specified. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Deserializes the data held in this object to the stream specified. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + + //----------------------------------------------------------------------- + /** + * Creates a list iterator for the sublist. + * + * @param subList the sublist to get an iterator for + * @param fromIndex the index to start from, relative to the sublist + * @return the list iterator for the sublist + */ + @Override + protected ListIterator createSubListListIterator(final LinkedSubList subList, final int fromIndex) { + final SubCursor cursor = new SubCursor(subList, fromIndex); + registerCursor(cursor); + return cursor; + } + + //----------------------------------------------------------------------- + /** + * An extended ListIterator that allows concurrent changes to + * the underlying list. + */ + public static class Cursor extends AbstractLinkedList.LinkedListIterator { + /** Is the cursor valid (not closed) */ + boolean valid = true; + /** Is the next index valid */ + boolean nextIndexValid = true; + /** Flag to indicate if the current element was removed by another object. */ + boolean currentRemovedByAnother = false; + + /** + * Constructs a new cursor. + * + * @param parent the parent list + * @param index the index to start from + */ + protected Cursor(final CursorableLinkedList parent, final int index) { + super(parent, index); + valid = true; + } + + /** + * Removes the item last returned by this iterator. + *

              + * There may have been subsequent alterations to the list + * since you obtained this item, however you can still remove it. + * You can even remove it if the item is no longer in the main list. + * However, you can't call this method on the same iterator more + * than once without calling next() or previous(). + * + * @throws IllegalStateException if there is no item to remove + */ + @Override + public void remove() { + // overridden, as the nodeRemoved() method updates the iterator + // state in the parent.removeNode() call below + if (current == null && currentRemovedByAnother) { // NOPMD + // quietly ignore, as the last returned node was removed + // by the list or some other iterator + // by ignoring it, we keep this iterator independent from + // other changes as much as possible + } else { + checkModCount(); + parent.removeNode(getLastNodeReturned()); + } + currentRemovedByAnother = false; + } + + /** + * Adds an object to the list. + * The object added here will be the new 'previous' in the iterator. + * + * @param obj the object to add + */ + @Override + public void add(final E obj) { + // overridden, as the nodeInserted() method updates the iterator state + super.add(obj); + // matches the (next.previous == node) clause in nodeInserted() + // thus next gets changed - reset it again here + next = next.next; + } + + // set is not overridden, as it works ok + // note that we want it to throw an exception if the element being + // set has been removed from the real list (compare this with the + // remove method where we silently ignore this case) + + /** + * Gets the index of the next element to be returned. + * + * @return the next index + */ + @Override + public int nextIndex() { + if (nextIndexValid == false) { + if (next == parent.header) { + nextIndex = parent.size(); + } else { + int pos = 0; + Node temp = parent.header.next; + while (temp != next) { + pos++; + temp = temp.next; + } + nextIndex = pos; + } + nextIndexValid = true; + } + return nextIndex; + } + + /** + * Handle event from the list when a node has changed. + * + * @param node the node that changed + */ + protected void nodeChanged(final Node node) { + // do nothing + } + + /** + * Handle event from the list when a node has been removed. + * + * @param node the node that was removed + */ + protected void nodeRemoved(final Node node) { + if (node == next && node == current) { + // state where next() followed by previous() + next = node.next; + current = null; + currentRemovedByAnother = true; + } else if (node == next) { + // state where next() not followed by previous() + // and we are matching next node + next = node.next; + currentRemovedByAnother = false; + } else if (node == current) { + // state where next() not followed by previous() + // and we are matching current (last returned) node + current = null; + currentRemovedByAnother = true; + nextIndex--; + } else { + nextIndexValid = false; + currentRemovedByAnother = false; + } + } + + /** + * Handle event from the list when a node has been added. + * + * @param node the node that was added + */ + protected void nodeInserted(final Node node) { + if (node.previous == current) { + next = node; + } else if (next.previous == node) { + next = node; + } else { + nextIndexValid = false; + } + } + + /** + * Override superclass modCount check, and replace it with our valid flag. + */ + @Override + protected void checkModCount() { + if (!valid) { + throw new ConcurrentModificationException("Cursor closed"); + } + } + + /** + * Mark this cursor as no longer being needed. Any resources + * associated with this cursor are immediately released. + * In previous versions of this class, it was mandatory to close + * all cursor objects to avoid memory leaks. It is no longer + * necessary to call this close method; an instance of this class + * can now be treated exactly like a normal iterator. + */ + public void close() { + if (valid) { + ((CursorableLinkedList) parent).unregisterCursor(this); + valid = false; + } + } + } + + //----------------------------------------------------------------------- + /** + * A cursor for the sublist based on LinkedSubListIterator. + * + * @since 3.2 + */ + protected static class SubCursor extends Cursor { + + /** The parent list */ + protected final LinkedSubList sub; + + /** + * Constructs a new cursor. + * + * @param sub the sub list + * @param index the index to start from + */ + protected SubCursor(final LinkedSubList sub, final int index) { + super((CursorableLinkedList) sub.parent, index + sub.offset); + this.sub = sub; + } + + @Override + public boolean hasNext() { + return nextIndex() < sub.size; + } + + @Override + public boolean hasPrevious() { + return previousIndex() >= 0; + } + + @Override + public int nextIndex() { + return super.nextIndex() - sub.offset; + } + + @Override + public void add(final E obj) { + super.add(obj); + sub.expectedModCount = parent.modCount; + sub.size++; + } + + @Override + public void remove() { + super.remove(); + sub.expectedModCount = parent.modCount; + sub.size--; + } + } + +} diff --git a/src/org/apache/commons/collections4/list/FixedSizeList.java b/src/org/apache/commons/collections4/list/FixedSizeList.java new file mode 100644 index 0000000..aa8ec6f --- /dev/null +++ b/src/org/apache/commons/collections4/list/FixedSizeList.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.collections4.BoundedCollection; +import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; + +/** + * Decorates another List to fix the size preventing add/remove. + *

              + * The add, remove, clear and retain operations are unsupported. + * The set method is allowed (as it doesn't change the list size). + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: FixedSizeList.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class FixedSizeList + extends AbstractSerializableListDecorator + implements BoundedCollection { + + /** Serialization version */ + private static final long serialVersionUID = -2218010673611160319L; + + /** + * Factory method to create a fixed size list. + * + * @param the type of the elements in the list + * @param list the list to decorate, must not be null + * @return a new fixed size list + * @throws NullPointerException if list is null + * @since 4.0 + */ + public static FixedSizeList fixedSizeList(final List list) { + return new FixedSizeList(list); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param list the list to decorate, must not be null + * @throws NullPointerException if list is null + */ + protected FixedSizeList(final List list) { + super(list); + } + + //----------------------------------------------------------------------- + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public void add(final int index, final E object) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public boolean addAll(final int index, final Collection coll) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public E get(final int index) { + return decorated().get(index); + } + + @Override + public int indexOf(final Object object) { + return decorated().indexOf(object); + } + + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public int lastIndexOf(final Object object) { + return decorated().lastIndexOf(object); + } + + @Override + public ListIterator listIterator() { + return new FixedSizeListIterator(decorated().listIterator(0)); + } + + @Override + public ListIterator listIterator(final int index) { + return new FixedSizeListIterator(decorated().listIterator(index)); + } + + @Override + public E remove(final int index) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException("List is fixed size"); + } + + @Override + public E set(final int index, final E object) { + return decorated().set(index, object); + } + + @Override + public List subList(final int fromIndex, final int toIndex) { + final List sub = decorated().subList(fromIndex, toIndex); + return new FixedSizeList(sub); + } + + /** + * List iterator that only permits changes via set() + */ + private class FixedSizeListIterator extends AbstractListIteratorDecorator { + protected FixedSizeListIterator(final ListIterator iterator) { + super(iterator); + } + @Override + public void remove() { + throw new UnsupportedOperationException("List is fixed size"); + } + @Override + public void add(final Object object) { + throw new UnsupportedOperationException("List is fixed size"); + } + } + + public boolean isFull() { + return true; + } + + public int maxSize() { + return size(); + } + +} diff --git a/src/org/apache/commons/collections4/list/GrowthList.java b/src/org/apache/commons/collections4/list/GrowthList.java new file mode 100644 index 0000000..92c2281 --- /dev/null +++ b/src/org/apache/commons/collections4/list/GrowthList.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Decorates another List to make it seamlessly grow when + * indices larger than the list size are used on add and set, + * avoiding most IndexOutOfBoundsExceptions. + *

              + * This class avoids errors by growing when a set or add method would + * normally throw an IndexOutOfBoundsException. + * Note that IndexOutOfBoundsException IS returned for invalid negative indices. + *

              + * Trying to set or add to an index larger than the size will cause the list + * to grow (using null elements). Clearly, care must be taken + * not to use excessively large indices, as the internal list will grow to + * match. + *

              + * Trying to use any method other than add or set with an invalid index will + * call the underlying list and probably result in an IndexOutOfBoundsException. + *

              + * Take care when using this list with null values, as + * null is the value added when growing the list. + *

              + * All sub-lists will access the underlying list directly, and will throw + * IndexOutOfBoundsExceptions. + *

              + * This class differs from {@link LazyList} because here growth occurs on + * set and add, where LazyList grows on get. However, they + * can be used together by decorating twice. + * + * @see LazyList + * @since 3.2 + * @version $Id: GrowthList.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class GrowthList extends AbstractSerializableListDecorator { + + /** Serialization version */ + private static final long serialVersionUID = -3620001881672L; + + /** + * Factory method to create a growth list. + * + * @param the type of the elements in the list + * @param list the list to decorate, must not be null + * @return a new growth list + * @throws NullPointerException if list is null + * @since 4.0 + */ + public static GrowthList growthList(final List list) { + return new GrowthList(list); + } + + //----------------------------------------------------------------------- + /** + * Constructor that uses an ArrayList internally. + */ + public GrowthList() { + super(new ArrayList()); + } + + /** + * Constructor that uses an ArrayList internally. + * + * @param initialSize the initial size of the ArrayList + * @throws IllegalArgumentException if initial size is invalid + */ + public GrowthList(final int initialSize) { + super(new ArrayList(initialSize)); + } + + /** + * Constructor that wraps (not copies). + * + * @param list the list to decorate, must not be null + * @throws NullPointerException if list is null + */ + protected GrowthList(final List list) { + super(list); + } + + //----------------------------------------------------------------------- + /** + * Decorate the add method to perform the growth behaviour. + *

              + * If the requested index is greater than the current size, the list will + * grow to the new size. Indices between the old size and the requested + * size will be filled with null. + *

              + * If the index is less than the current size, the value will be added to + * the underlying list directly. + * If the index is less than zero, the underlying list is called, which + * will probably throw an IndexOutOfBoundsException. + * + * @param index the index to add at + * @param element the object to add at the specified index + * @throws UnsupportedOperationException if the underlying list doesn't implement set + * @throws ClassCastException if the underlying list rejects the element + * @throws IllegalArgumentException if the underlying list rejects the element + */ + @Override + public void add(final int index, final E element) { + final int size = decorated().size(); + if (index > size) { + decorated().addAll(Collections.nCopies(index - size, null)); + } + decorated().add(index, element); + } + + //----------------------------------------------------------------------- + /** + * Decorate the addAll method to perform the growth behaviour. + *

              + * If the requested index is greater than the current size, the list will + * grow to the new size. Indices between the old size and the requested + * size will be filled with null. + *

              + * If the index is less than the current size, the values will be added to + * the underlying list directly. + * If the index is less than zero, the underlying list is called, which + * will probably throw an IndexOutOfBoundsException. + * + * @param index the index to add at + * @param coll the collection to add at the specified index + * @return true if the list changed + * @throws UnsupportedOperationException if the underlying list doesn't implement set + * @throws ClassCastException if the underlying list rejects the element + * @throws IllegalArgumentException if the underlying list rejects the element + */ + @Override + public boolean addAll(final int index, final Collection coll) { + final int size = decorated().size(); + boolean result = false; + if (index > size) { + decorated().addAll(Collections.nCopies(index - size, null)); + result = true; + } + return decorated().addAll(index, coll) | result; + } + + //----------------------------------------------------------------------- + /** + * Decorate the set method to perform the growth behaviour. + *

              + * If the requested index is greater than the current size, the list will + * grow to the new size. Indices between the old size and the requested + * size will be filled with null. + *

              + * If the index is less than the current size, the value will be set onto + * the underlying list directly. + * If the index is less than zero, the underlying list is called, which + * will probably throw an IndexOutOfBoundsException. + * + * @param index the index to set + * @param element the object to set at the specified index + * @return the object previously at that index + * @throws UnsupportedOperationException if the underlying list doesn't implement set + * @throws ClassCastException if the underlying list rejects the element + * @throws IllegalArgumentException if the underlying list rejects the element + */ + @Override + public E set(final int index, final E element) { + final int size = decorated().size(); + if (index >= size) { + decorated().addAll(Collections.nCopies(index - size + 1, null)); + } + return decorated().set(index, element); + } + +} diff --git a/src/org/apache/commons/collections4/list/LazyList.java b/src/org/apache/commons/collections4/list/LazyList.java new file mode 100644 index 0000000..c932209 --- /dev/null +++ b/src/org/apache/commons/collections4/list/LazyList.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.List; + +import org.apache.commons.collections4.Factory; + +/** + * Decorates another List to create objects in the list on demand. + *

              + * When the {@link #get(int)} method is called with an index greater than + * the size of the list, the list will automatically grow in size and return + * a new object from the specified factory. The gaps will be filled by null. + * If a get method call encounters a null, it will be replaced with a new + * object from the factory. Thus this list is unsuitable for storing null + * objects. + *

              + * For instance: + * + *

              + * Factory<Date> factory = new Factory<Date>() {
              + *     public Date create() {
              + *         return new Date();
              + *     }
              + * }
              + * List<Date> lazy = LazyList.decorate(new ArrayList<Date>(), factory);
              + * Date date = lazy.get(3);
              + * 
              + * + * After the above code is executed, date will contain + * a new Date instance. Furthermore, that Date + * instance is the fourth element in the list. The first, second, + * and third element are all set to null. + *

              + * This class differs from {@link GrowthList} because here growth occurs on + * get, where GrowthList grows on set and add. However, they + * could easily be used together by decorating twice. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @see GrowthList + * @since 3.0 + * @version $Id: LazyList.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class LazyList extends AbstractSerializableListDecorator { + + /** Serialization version */ + private static final long serialVersionUID = -1708388017160694542L; + + /** The factory to use to lazily instantiate the objects */ + private final Factory factory; + + /** + * Factory method to create a lazily instantiating list. + * + * @param the type of the elements in the list + * @param list the list to decorate, must not be null + * @param factory the factory to use for creation, must not be null + * @return a new lazy list + * @throws NullPointerException if list or factory is null + * @since 4.0 + */ + public static LazyList lazyList(final List list, final Factory factory) { + return new LazyList(list, factory); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param list the list to decorate, must not be null + * @param factory the factory to use for creation, must not be null + * @throws NullPointerException if list or factory is null + */ + protected LazyList(final List list, final Factory factory) { + super(list); + if (factory == null) { + throw new IllegalArgumentException("Factory must not be null"); + } + this.factory = factory; + } + + //----------------------------------------------------------------------- + /** + * Decorate the get method to perform the lazy behaviour. + *

              + * If the requested index is greater than the current size, the list will + * grow to the new size and a new object will be returned from the factory. + * Indexes in-between the old size and the requested size are left with a + * placeholder that is replaced with a factory object when requested. + * + * @param index the index to retrieve + * @return the element at the given index + */ + @Override + public E get(final int index) { + final int size = decorated().size(); + if (index < size) { + // within bounds, get the object + E object = decorated().get(index); + if (object == null) { + // item is a place holder, create new one, set and return + object = factory.create(); + decorated().set(index, object); + return object; + } + // good and ready to go + return object; + } + // we have to grow the list + for (int i = size; i < index; i++) { + decorated().add(null); + } + // create our last object, set and return + final E object = factory.create(); + decorated().add(object); + return object; + } + + @Override + public List subList(final int fromIndex, final int toIndex) { + final List sub = decorated().subList(fromIndex, toIndex); + return new LazyList(sub, factory); + } + +} diff --git a/src/org/apache/commons/collections4/list/NodeCachingLinkedList.java b/src/org/apache/commons/collections4/list/NodeCachingLinkedList.java new file mode 100644 index 0000000..f7b84b1 --- /dev/null +++ b/src/org/apache/commons/collections4/list/NodeCachingLinkedList.java @@ -0,0 +1,244 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; + +/** + * A List implementation that stores a cache of internal Node objects + * in an effort to reduce wasteful object creation. + *

              + * A linked list creates one Node for each item of data added. This can result in + * a lot of object creation and garbage collection. This implementation seeks to + * avoid that by maintaining a store of cached nodes. + *

              + * This implementation is suitable for long-lived lists where both add and remove + * are used. Short-lived lists, or lists which only grow will have worse performance + * using this class. + *

              + * Note that this implementation is not synchronized. + * + * @since 3.0 + * @version $Id: NodeCachingLinkedList.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public class NodeCachingLinkedList extends AbstractLinkedList implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 6897789178562232073L; + + /** + * The default value for {@link #maximumCacheSize}. + */ + private static final int DEFAULT_MAXIMUM_CACHE_SIZE = 20; + + /** + * The first cached node, or null if no nodes are cached. + * Cached nodes are stored in a singly-linked list with + * next pointing to the next element. + */ + private transient Node firstCachedNode; + + /** + * The size of the cache. + */ + private transient int cacheSize; + + /** + * The maximum size of the cache. + */ + private int maximumCacheSize; + + //----------------------------------------------------------------------- + /** + * Constructor that creates. + */ + public NodeCachingLinkedList() { + this(DEFAULT_MAXIMUM_CACHE_SIZE); + } + + /** + * Constructor that copies the specified collection + * + * @param coll the collection to copy + */ + public NodeCachingLinkedList(final Collection coll) { + super(coll); + this.maximumCacheSize = DEFAULT_MAXIMUM_CACHE_SIZE; + } + + /** + * Constructor that species the maximum cache size. + * + * @param maximumCacheSize the maximum cache size + */ + public NodeCachingLinkedList(final int maximumCacheSize) { + super(); + this.maximumCacheSize = maximumCacheSize; + init(); // must call init() as use super(); + } + + //----------------------------------------------------------------------- + /** + * Gets the maximum size of the cache. + * + * @return the maximum cache size + */ + protected int getMaximumCacheSize() { + return maximumCacheSize; + } + + /** + * Sets the maximum size of the cache. + * + * @param maximumCacheSize the new maximum cache size + */ + protected void setMaximumCacheSize(final int maximumCacheSize) { + this.maximumCacheSize = maximumCacheSize; + shrinkCacheToMaximumSize(); + } + + /** + * Reduce the size of the cache to the maximum, if necessary. + */ + protected void shrinkCacheToMaximumSize() { + // Rich Dougherty: This could be more efficient. + while (cacheSize > maximumCacheSize) { + getNodeFromCache(); + } + } + + /** + * Gets a node from the cache. If a node is returned, then the value of + * {@link #cacheSize} is decreased accordingly. The node that is returned + * will have null values for next, previous and element. + * + * @return a node, or null if there are no nodes in the cache. + */ + protected Node getNodeFromCache() { + if (cacheSize == 0) { + return null; + } + final Node cachedNode = firstCachedNode; + firstCachedNode = cachedNode.next; + cachedNode.next = null; // This should be changed anyway, but defensively + // set it to null. + cacheSize--; + return cachedNode; + } + + /** + * Checks whether the cache is full. + * + * @return true if the cache is full + */ + protected boolean isCacheFull() { + return cacheSize >= maximumCacheSize; + } + + /** + * Adds a node to the cache, if the cache isn't full. + * The node's contents are cleared to so they can be garbage collected. + * + * @param node the node to add to the cache + */ + protected void addNodeToCache(final Node node) { + if (isCacheFull()) { + // don't cache the node. + return; + } + // clear the node's contents and add it to the cache. + final Node nextCachedNode = firstCachedNode; + node.previous = null; + node.next = nextCachedNode; + node.setValue(null); + firstCachedNode = node; + cacheSize++; + } + + //----------------------------------------------------------------------- + /** + * Creates a new node, either by reusing one from the cache or creating + * a new one. + * + * @param value value of the new node + * @return the newly created node + */ + @Override + protected Node createNode(final E value) { + final Node cachedNode = getNodeFromCache(); + if (cachedNode == null) { + return super.createNode(value); + } + cachedNode.setValue(value); + return cachedNode; + } + + /** + * Removes the node from the list, storing it in the cache for reuse + * if the cache is not yet full. + * + * @param node the node to remove + */ + @Override + protected void removeNode(final Node node) { + super.removeNode(node); + addNodeToCache(node); + } + + /** + * Removes all the nodes from the list, storing as many as required in the + * cache for reuse. + * + */ + @Override + protected void removeAllNodes() { + // Add the removed nodes to the cache, then remove the rest. + // We can add them to the cache before removing them, since + // {@link AbstractLinkedList.removeAllNodes()} removes the + // nodes by removing references directly from {@link #header}. + final int numberOfNodesToCache = Math.min(size, maximumCacheSize - cacheSize); + Node node = header.next; + for (int currentIndex = 0; currentIndex < numberOfNodesToCache; currentIndex++) { + final Node oldNode = node; + node = node.next; + addNodeToCache(oldNode); + } + super.removeAllNodes(); + } + + //----------------------------------------------------------------------- + /** + * Serializes the data held in this object to the stream specified. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Deserializes the data held in this object to the stream specified. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + +} diff --git a/src/org/apache/commons/collections4/list/PredicatedList.java b/src/org/apache/commons/collections4/list/PredicatedList.java new file mode 100644 index 0000000..22d21dd --- /dev/null +++ b/src/org/apache/commons/collections4/list/PredicatedList.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.Collection; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.collection.PredicatedCollection; +import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator; + +/** + * Decorates another List to validate that all additions + * match a specified predicate. + *

              + * This list exists to provide validation for the decorated list. + * It is normally created to decorate an empty list. + * If an object cannot be added to the list, an IllegalArgumentException is thrown. + *

              + * One usage would be to ensure that no null entries are added to the list. + *

              + * {@code
              + * List list =
              + *   PredicatedList.predicatedList(new ArrayList(), PredicateUtils.notNullPredicate());
              + * }
              + * 
              + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: PredicatedList.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedList extends PredicatedCollection implements List { + + /** Serialization version */ + private static final long serialVersionUID = -5722039223898659102L; + + /** + * Factory method to create a predicated (validating) list. + *

              + * If there are any elements already in the list being decorated, they + * are validated. + * + * @param the type of the elements in the list + * @param list the list to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated list + * @throws NullPointerException if list or predicate is null + * @throws IllegalArgumentException if the list contains invalid elements + * @since 4.0 + */ + public static PredicatedList predicatedList(final List list, final Predicate predicate) { + return new PredicatedList(list, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the list being decorated, they + * are validated. + * + * @param list the list to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if list or predicate is null + * @throws IllegalArgumentException if the list contains invalid elements + */ + protected PredicatedList(final List list, final Predicate predicate) { + super(list, predicate); + } + + /** + * Gets the list being decorated. + * + * @return the decorated list + */ + @Override + protected List decorated() { + return (List) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + public E get(final int index) { + return decorated().get(index); + } + + public int indexOf(final Object object) { + return decorated().indexOf(object); + } + + public int lastIndexOf(final Object object) { + return decorated().lastIndexOf(object); + } + + public E remove(final int index) { + return decorated().remove(index); + } + + //----------------------------------------------------------------------- + + public void add(final int index, final E object) { + validate(object); + decorated().add(index, object); + } + + public boolean addAll(final int index, final Collection coll) { + for (final E aColl : coll) { + validate(aColl); + } + return decorated().addAll(index, coll); + } + + public ListIterator listIterator() { + return listIterator(0); + } + + public ListIterator listIterator(final int i) { + return new PredicatedListIterator(decorated().listIterator(i)); + } + + public E set(final int index, final E object) { + validate(object); + return decorated().set(index, object); + } + + public List subList(final int fromIndex, final int toIndex) { + final List sub = decorated().subList(fromIndex, toIndex); + return new PredicatedList(sub, predicate); + } + + /** + * Inner class Iterator for the PredicatedList + */ + protected class PredicatedListIterator extends AbstractListIteratorDecorator { + + /** + * Create a new predicated list iterator. + * + * @param iterator the list iterator to decorate + */ + protected PredicatedListIterator(final ListIterator iterator) { + super(iterator); + } + + @Override + public void add(final E object) { + validate(object); + getListIterator().add(object); + } + + @Override + public void set(final E object) { + validate(object); + getListIterator().set(object); + } + } + +} diff --git a/src/org/apache/commons/collections4/list/SetUniqueList.java b/src/org/apache/commons/collections4/list/SetUniqueList.java new file mode 100644 index 0000000..63da3ea --- /dev/null +++ b/src/org/apache/commons/collections4/list/SetUniqueList.java @@ -0,0 +1,424 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; +import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates a List to ensure that no duplicates are present much + * like a Set. + *

              + * The List interface makes certain assumptions/requirements. This + * implementation breaks these in certain ways, but this is merely the result of + * rejecting duplicates. Each violation is explained in the method, but it + * should not affect you. Bear in mind that Sets require immutable objects to + * function correctly. + *

              + * The {@link org.apache.commons.collections4.set.ListOrderedSet ListOrderedSet} + * class provides an alternative approach, by wrapping an existing Set and + * retaining insertion order in the iterator. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: SetUniqueList.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class SetUniqueList extends AbstractSerializableListDecorator { + + /** Serialization version. */ + private static final long serialVersionUID = 7196982186153478694L; + + /** Internal Set to maintain uniqueness. */ + private final Set set; + + /** + * Factory method to create a SetList using the supplied list to retain order. + *

              + * If the list contains duplicates, these are removed (first indexed one + * kept). A HashSet is used for the set behaviour. + * + * @param the element type + * @param list the list to decorate, must not be null + * @return a new {@link SetUniqueList} + * @throws NullPointerException if list is null + * @since 4.0 + */ + public static SetUniqueList setUniqueList(final List list) { + if (list == null) { + throw new NullPointerException("List must not be null"); + } + if (list.isEmpty()) { + return new SetUniqueList(list, new HashSet()); + } + final List temp = new ArrayList(list); + list.clear(); + final SetUniqueList sl = new SetUniqueList(list, new HashSet()); + sl.addAll(temp); + return sl; + } + + // ----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies) the List and specifies the set to use. + *

              + * The set and list must both be correctly initialised to the same elements. + * + * @param set the set to decorate, must not be null + * @param list the list to decorate, must not be null + * @throws NullPointerException if set or list is null + */ + protected SetUniqueList(final List list, final Set set) { + super(list); + if (set == null) { + throw new NullPointerException("Set must not be null"); + } + this.set = set; + } + + // ----------------------------------------------------------------------- + /** + * Gets an unmodifiable view as a Set. + * + * @return an unmodifiable set view + */ + public Set asSet() { + return UnmodifiableSet.unmodifiableSet(set); + } + + // ----------------------------------------------------------------------- + /** + * Adds an element to the list if it is not already present. + *

              + * (Violation) The List interface requires that this + * method returns true always. However this class may return + * false because of the Set behaviour. + * + * @param object the object to add + * @return true if object was added + */ + @Override + public boolean add(final E object) { + // gets initial size + final int sizeBefore = size(); + + // adds element if unique + add(size(), object); + + // compares sizes to detect if collection changed + return sizeBefore != size(); + } + + /** + * Adds an element to a specific index in the list if it is not already + * present. + *

              + * (Violation) The List interface makes the assumption + * that the element is always inserted. This may not happen with this + * implementation. + * + * @param index the index to insert at + * @param object the object to add + */ + @Override + public void add(final int index, final E object) { + // adds element if it is not contained already + if (set.contains(object) == false) { + super.add(index, object); + set.add(object); + } + } + + /** + * Adds a collection of objects to the end of the list avoiding duplicates. + *

              + * Only elements that are not already in this list will be added, and + * duplicates from the specified collection will be ignored. + *

              + * (Violation) The List interface makes the assumption + * that the elements are always inserted. This may not happen with this + * implementation. + * + * @param coll the collection to add in iterator order + * @return true if this collection changed + */ + @Override + public boolean addAll(final Collection coll) { + return addAll(size(), coll); + } + + /** + * Adds a collection of objects a specific index in the list avoiding + * duplicates. + *

              + * Only elements that are not already in this list will be added, and + * duplicates from the specified collection will be ignored. + *

              + * (Violation) The List interface makes the assumption + * that the elements are always inserted. This may not happen with this + * implementation. + * + * @param index the index to insert at + * @param coll the collection to add in iterator order + * @return true if this collection changed + */ + @Override + public boolean addAll(final int index, final Collection coll) { + final List temp = new ArrayList(); + for (final E e : coll) { + if (set.add(e)) { + temp.add(e); + } + } + return super.addAll(index, temp); + } + + // ----------------------------------------------------------------------- + /** + * Sets the value at the specified index avoiding duplicates. + *

              + * The object is set into the specified index. Afterwards, any previous + * duplicate is removed. If the object is not already in the list then a + * normal set occurs. If it is present, then the old version is removed. + * + * @param index the index to insert at + * @param object the object to set + * @return the previous object + */ + @Override + public E set(final int index, final E object) { + final int pos = indexOf(object); + final E removed = super.set(index, object); + + if (pos != -1 && pos != index) { + // the object is already in the unique list + // (and it hasn't been swapped with itself) + super.remove(pos); // remove the duplicate by index + } + + set.remove(removed); // remove the item deleted by the set + set.add(object); // add the new item to the unique set + + return removed; // return the item deleted by the set + } + + @Override + public boolean remove(final Object object) { + final boolean result = set.remove(object); + if (result) { + super.remove(object); + } + return result; + } + + @Override + public E remove(final int index) { + final E result = super.remove(index); + set.remove(result); + return result; + } + + @Override + public boolean removeAll(final Collection coll) { + boolean result = false; + for (final Object name : coll) { + result |= remove(name); + } + return result; + } + + /** + * {@inheritDoc} + *

              + * This implementation iterates over the elements of this list, checking + * each element in turn to see if it's contained in coll. + * If it's not contained, it's removed from this list. As a consequence, + * it is advised to use a collection type for coll that provides + * a fast (e.g. O(1)) implementation of {@link Collection#contains(Object)}. + */ + @Override + public boolean retainAll(final Collection coll) { + boolean result = set.retainAll(coll); + if (result == false) { + return false; + } + if (set.size() == 0) { + super.clear(); + } else { + // use the set as parameter for the call to retainAll to improve performance + super.retainAll(set); + } + return result; + } + + @Override + public void clear() { + super.clear(); + set.clear(); + } + + @Override + public boolean contains(final Object object) { + return set.contains(object); + } + + @Override + public boolean containsAll(final Collection coll) { + return set.containsAll(coll); + } + + @Override + public Iterator iterator() { + return new SetListIterator(super.iterator(), set); + } + + @Override + public ListIterator listIterator() { + return new SetListListIterator(super.listIterator(), set); + } + + @Override + public ListIterator listIterator(final int index) { + return new SetListListIterator(super.listIterator(index), set); + } + + /** + * {@inheritDoc} + *

              + * NOTE: from 4.0, an unmodifiable list will be returned, as changes to the + * subList can invalidate the parent list. + */ + @Override + public List subList(final int fromIndex, final int toIndex) { + final List superSubList = super.subList(fromIndex, toIndex); + final Set subSet = createSetBasedOnList(set, superSubList); + return ListUtils.unmodifiableList(new SetUniqueList(superSubList, subSet)); + } + + /** + * Create a new {@link Set} with the same type as the provided {@code set} + * and populate it with all elements of {@code list}. + * + * @param set the {@link Set} to be used as return type, must not be null + * @param list the {@link List} to populate the {@link Set} + * @return a new {@link Set} populated with all elements of the provided + * {@link List} + */ + @SuppressWarnings("unchecked") + protected Set createSetBasedOnList(final Set set, final List list) { + Set subSet; + if (set.getClass().equals(HashSet.class)) { + subSet = new HashSet(list.size()); + } else { + try { + subSet = set.getClass().newInstance(); + } catch (final InstantiationException ie) { + subSet = new HashSet(); + } catch (final IllegalAccessException iae) { + subSet = new HashSet(); + } + } + subSet.addAll(list); + return subSet; + } + + // ----------------------------------------------------------------------- + /** + * Inner class iterator. + */ + static class SetListIterator extends AbstractIteratorDecorator { + + private final Set set; + private E last = null; + + protected SetListIterator(final Iterator it, final Set set) { + super(it); + this.set = set; + } + + @Override + public E next() { + last = super.next(); + return last; + } + + @Override + public void remove() { + super.remove(); + set.remove(last); + last = null; + } + } + + /** + * Inner class iterator. + */ + static class SetListListIterator extends + AbstractListIteratorDecorator { + + private final Set set; + private E last = null; + + protected SetListListIterator(final ListIterator it, final Set set) { + super(it); + this.set = set; + } + + @Override + public E next() { + last = super.next(); + return last; + } + + @Override + public E previous() { + last = super.previous(); + return last; + } + + @Override + public void remove() { + super.remove(); + set.remove(last); + last = null; + } + + @Override + public void add(final E object) { + if (set.contains(object) == false) { + super.add(object); + set.add(object); + } + } + + @Override + public void set(final E object) { + throw new UnsupportedOperationException("ListIterator does not support set"); + } + } + +} diff --git a/src/org/apache/commons/collections4/list/TransformedList.java b/src/org/apache/commons/collections4/list/TransformedList.java new file mode 100644 index 0000000..c52793e --- /dev/null +++ b/src/org/apache/commons/collections4/list/TransformedList.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.Collection; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.collection.TransformedCollection; +import org.apache.commons.collections4.iterators.AbstractListIteratorDecorator; + +/** + * Decorates another List to transform objects that are added. + *

              + * The add and set methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: TransformedList.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedList extends TransformedCollection implements List { + + /** Serialization version */ + private static final long serialVersionUID = 1077193035000013141L; + + /** + * Factory method to create a transforming list. + *

              + * If there are any elements already in the list being decorated, they + * are NOT transformed. + * Contrast this with {@link #transformedList(List, Transformer)}. + * + * @param the type of the elements in the list + * @param list the list to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed list + * @throws NullPointerException if list or transformer is null + * @since 4.0 + */ + public static TransformedList transformingList(final List list, + final Transformer transformer) { + return new TransformedList(list, transformer); + } + + /** + * Factory method to create a transforming list that will transform + * existing contents of the specified list. + *

              + * If there are any elements already in the list being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingList(List, Transformer)}. + * + * @param the type of the elements in the list + * @param list the list to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed List + * @throws NullPointerException if list or transformer is null + * @since 4.0 + */ + public static TransformedList transformedList(final List list, + final Transformer transformer) { + final TransformedList decorated = new TransformedList(list, transformer); + if (list.size() > 0) { + @SuppressWarnings("unchecked") // list is of type E + final E[] values = (E[]) list.toArray(); // NOPMD - false positive for generics + list.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the list being decorated, they + * are NOT transformed. + * + * @param list the list to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if list or transformer is null + */ + protected TransformedList(final List list, final Transformer transformer) { + super(list, transformer); + } + + /** + * Gets the decorated list. + * + * @return the decorated list + */ + protected List getList() { + return (List) decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + public E get(final int index) { + return getList().get(index); + } + + public int indexOf(final Object object) { + return getList().indexOf(object); + } + + public int lastIndexOf(final Object object) { + return getList().lastIndexOf(object); + } + + public E remove(final int index) { + return getList().remove(index); + } + + //----------------------------------------------------------------------- + + public void add(final int index, E object) { + object = transform(object); + getList().add(index, object); + } + + public boolean addAll(final int index, Collection coll) { + coll = transform(coll); + return getList().addAll(index, coll); + } + + public ListIterator listIterator() { + return listIterator(0); + } + + public ListIterator listIterator(final int i) { + return new TransformedListIterator(getList().listIterator(i)); + } + + public E set(final int index, E object) { + object = transform(object); + return getList().set(index, object); + } + + public List subList(final int fromIndex, final int toIndex) { + final List sub = getList().subList(fromIndex, toIndex); + return new TransformedList(sub, transformer); + } + + /** + * Inner class Iterator for the TransformedList + */ + protected class TransformedListIterator extends AbstractListIteratorDecorator { + + /** + * Create a new transformed list iterator. + * + * @param iterator the list iterator to decorate + */ + protected TransformedListIterator(final ListIterator iterator) { + super(iterator); + } + + @Override + public void add(E object) { + object = transform(object); + getListIterator().add(object); + } + + @Override + public void set(E object) { + object = transform(object); + getListIterator().set(object); + } + } + +} diff --git a/src/org/apache/commons/collections4/list/TreeList.java b/src/org/apache/commons/collections4/list/TreeList.java new file mode 100644 index 0000000..5300d14 --- /dev/null +++ b/src/org/apache/commons/collections4/list/TreeList.java @@ -0,0 +1,1120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.AbstractList; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Deque; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.OrderedIterator; + +/** + * A List implementation that is optimised for fast insertions and + * removals at any index in the list. + *

              + * This list implementation utilises a tree structure internally to ensure that + * all insertions and removals are O(log n). This provides much faster performance + * than both an ArrayList and a LinkedList where elements + * are inserted and removed repeatedly from anywhere in the list. + *

              + * The following relative performance statistics are indicative of this class: + *

              + *              get  add  insert  iterate  remove
              + * TreeList       3    5       1       2       1
              + * ArrayList      1    1      40       1      40
              + * LinkedList  5800    1     350       2     325
              + * 
              + * ArrayList is a good general purpose list implementation. + * It is faster than TreeList for most operations except inserting + * and removing in the middle of the list. ArrayList also uses less + * memory as TreeList uses one object per entry. + *

              + * LinkedList is rarely a good choice of implementation. + * TreeList is almost always a good replacement for it, although it + * does use slightly more memory. + * + * @since 3.1 + * @version $Id: TreeList.java 1681434 2015-05-24 10:49:58Z tn $ + */ +public class TreeList extends AbstractList { +// add; toArray; iterator; insert; get; indexOf; remove +// TreeList = 1260;7360;3080; 160; 170;3400; 170; +// ArrayList = 220;1480;1760; 6870; 50;1540; 7200; +// LinkedList = 270;7360;3350;55860;290720;2910;55200; + + /** The root node in the AVL tree */ + private AVLNode root; + + /** The current size of the list */ + private int size; + + //----------------------------------------------------------------------- + /** + * Constructs a new empty list. + */ + public TreeList() { + super(); + } + + /** + * Constructs a new empty list that copies the specified collection. + * + * @param coll the collection to copy + * @throws NullPointerException if the collection is null + */ + public TreeList(final Collection coll) { + super(); + if (!coll.isEmpty()) { + root = new AVLNode(coll); + size = coll.size(); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the element at the specified index. + * + * @param index the index to retrieve + * @return the element at the specified index + */ + @Override + public E get(final int index) { + checkInterval(index, 0, size() - 1); + return root.get(index).getValue(); + } + + /** + * Gets the current size of the list. + * + * @return the current size + */ + @Override + public int size() { + return size; + } + + /** + * Gets an iterator over the list. + * + * @return an iterator over the list + */ + @Override + public Iterator iterator() { + // override to go 75% faster + return listIterator(0); + } + + /** + * Gets a ListIterator over the list. + * + * @return the new iterator + */ + @Override + public ListIterator listIterator() { + // override to go 75% faster + return listIterator(0); + } + + /** + * Gets a ListIterator over the list. + * + * @param fromIndex the index to start from + * @return the new iterator + */ + @Override + public ListIterator listIterator(final int fromIndex) { + // override to go 75% faster + // cannot use EmptyIterator as iterator.add() must work + checkInterval(fromIndex, 0, size()); + return new TreeListIterator(this, fromIndex); + } + + /** + * Searches for the index of an object in the list. + * + * @param object the object to search + * @return the index of the object, -1 if not found + */ + @Override + public int indexOf(final Object object) { + // override to go 75% faster + if (root == null) { + return -1; + } + return root.indexOf(object, root.relativePosition); + } + + /** + * Searches for the presence of an object in the list. + * + * @param object the object to check + * @return true if the object is found + */ + @Override + public boolean contains(final Object object) { + return indexOf(object) >= 0; + } + + /** + * Converts the list into an array. + * + * @return the list as an array + */ + @Override + public Object[] toArray() { + // override to go 20% faster + final Object[] array = new Object[size()]; + if (root != null) { + root.toArray(array, root.relativePosition); + } + return array; + } + + //----------------------------------------------------------------------- + /** + * Adds a new element to the list. + * + * @param index the index to add before + * @param obj the element to add + */ + @Override + public void add(final int index, final E obj) { + modCount++; + checkInterval(index, 0, size()); + if (root == null) { + root = new AVLNode(index, obj, null, null); + } else { + root = root.insert(index, obj); + } + size++; + } + + /** + * Appends all of the elements in the specified collection to the end of this list, + * in the order that they are returned by the specified collection's Iterator. + *

              + * This method runs in O(n + log m) time, where m is + * the size of this list and n is the size of {@code c}. + * + * @param c the collection to be added to this list + * @return {@code true} if this list changed as a result of the call + * @throws NullPointerException {@inheritDoc} + */ + @Override + public boolean addAll(final Collection c) { + if (c.isEmpty()) { + return false; + } + modCount += c.size(); + final AVLNode cTree = new AVLNode(c); + root = root == null ? cTree : root.addAll(cTree, size); + size += c.size(); + return true; + } + + /** + * Sets the element at the specified index. + * + * @param index the index to set + * @param obj the object to store at the specified index + * @return the previous object at that index + * @throws IndexOutOfBoundsException if the index is invalid + */ + @Override + public E set(final int index, final E obj) { + checkInterval(index, 0, size() - 1); + final AVLNode node = root.get(index); + final E result = node.value; + node.setValue(obj); + return result; + } + + /** + * Removes the element at the specified index. + * + * @param index the index to remove + * @return the previous object at that index + */ + @Override + public E remove(final int index) { + modCount++; + checkInterval(index, 0, size() - 1); + final E result = get(index); + root = root.remove(index); + size--; + return result; + } + + /** + * Clears the list, removing all entries. + */ + @Override + public void clear() { + modCount++; + root = null; + size = 0; + } + + //----------------------------------------------------------------------- + /** + * Checks whether the index is valid. + * + * @param index the index to check + * @param startIndex the first allowed index + * @param endIndex the last allowed index + * @throws IndexOutOfBoundsException if the index is invalid + */ + private void checkInterval(final int index, final int startIndex, final int endIndex) { + if (index < startIndex || index > endIndex) { + throw new IndexOutOfBoundsException("Invalid index:" + index + ", size=" + size()); + } + } + + //----------------------------------------------------------------------- + /** + * Implements an AVLNode which keeps the offset updated. + *

              + * This node contains the real work. + * TreeList is just there to implement {@link java.util.List}. + * The nodes don't know the index of the object they are holding. They + * do know however their position relative to their parent node. + * This allows to calculate the index of a node while traversing the tree. + *

              + * The Faedelung calculation stores a flag for both the left and right child + * to indicate if they are a child (false) or a link as in linked list (true). + */ + static class AVLNode { + /** The left child node or the predecessor if {@link #leftIsPrevious}.*/ + private AVLNode left; + /** Flag indicating that left reference is not a subtree but the predecessor. */ + private boolean leftIsPrevious; + /** The right child node or the successor if {@link #rightIsNext}. */ + private AVLNode right; + /** Flag indicating that right reference is not a subtree but the successor. */ + private boolean rightIsNext; + /** How many levels of left/right are below this one. */ + private int height; + /** The relative position, root holds absolute position. */ + private int relativePosition; + /** The stored element. */ + private E value; + + /** + * Constructs a new node with a relative position. + * + * @param relativePosition the relative position of the node + * @param obj the value for the node + * @param rightFollower the node with the value following this one + * @param leftFollower the node with the value leading this one + */ + private AVLNode(final int relativePosition, final E obj, + final AVLNode rightFollower, final AVLNode leftFollower) { + this.relativePosition = relativePosition; + value = obj; + rightIsNext = true; + leftIsPrevious = true; + right = rightFollower; + left = leftFollower; + } + + /** + * Constructs a new AVL tree from a collection. + *

              + * The collection must be nonempty. + * + * @param coll a nonempty collection + */ + private AVLNode(final Collection coll) { + this(coll.iterator(), 0, coll.size() - 1, 0, null, null); + } + + /** + * Constructs a new AVL tree from a collection. + *

              + * This is a recursive helper for {@link #AVLNode(Collection)}. A call + * to this method will construct the subtree for elements {@code start} + * through {@code end} of the collection, assuming the iterator + * {@code e} already points at element {@code start}. + * + * @param iterator an iterator over the collection, which should already point + * to the element at index {@code start} within the collection + * @param start the index of the first element in the collection that + * should be in this subtree + * @param end the index of the last element in the collection that + * should be in this subtree + * @param absolutePositionOfParent absolute position of this node's + * parent, or 0 if this node is the root + * @param prev the {@code AVLNode} corresponding to element (start - 1) + * of the collection, or null if start is 0 + * @param next the {@code AVLNode} corresponding to element (end + 1) + * of the collection, or null if end is the last element of the collection + */ + private AVLNode(final Iterator iterator, final int start, final int end, + final int absolutePositionOfParent, final AVLNode prev, final AVLNode next) { + final int mid = start + (end - start) / 2; + if (start < mid) { + left = new AVLNode(iterator, start, mid - 1, mid, prev, this); + } else { + leftIsPrevious = true; + left = prev; + } + value = iterator.next(); + relativePosition = mid - absolutePositionOfParent; + if (mid < end) { + right = new AVLNode(iterator, mid + 1, end, mid, this, next); + } else { + rightIsNext = true; + right = next; + } + recalcHeight(); + } + + /** + * Gets the value. + * + * @return the value of this node + */ + E getValue() { + return value; + } + + /** + * Sets the value. + * + * @param obj the value to store + */ + void setValue(final E obj) { + this.value = obj; + } + + /** + * Locate the element with the given index relative to the + * offset of the parent of this node. + */ + AVLNode get(final int index) { + final int indexRelativeToMe = index - relativePosition; + + if (indexRelativeToMe == 0) { + return this; + } + + final AVLNode nextNode = indexRelativeToMe < 0 ? getLeftSubTree() : getRightSubTree(); + if (nextNode == null) { + return null; + } + return nextNode.get(indexRelativeToMe); + } + + /** + * Locate the index that contains the specified object. + */ + int indexOf(final Object object, final int index) { + if (getLeftSubTree() != null) { + final int result = left.indexOf(object, index + left.relativePosition); + if (result != -1) { + return result; + } + } + if (value == null ? value == object : value.equals(object)) { + return index; + } + if (getRightSubTree() != null) { + return right.indexOf(object, index + right.relativePosition); + } + return -1; + } + + /** + * Stores the node and its children into the array specified. + * + * @param array the array to be filled + * @param index the index of this node + */ + void toArray(final Object[] array, final int index) { + array[index] = value; + if (getLeftSubTree() != null) { + left.toArray(array, index + left.relativePosition); + } + if (getRightSubTree() != null) { + right.toArray(array, index + right.relativePosition); + } + } + + /** + * Gets the next node in the list after this one. + * + * @return the next node + */ + AVLNode next() { + if (rightIsNext || right == null) { + return right; + } + return right.min(); + } + + /** + * Gets the node in the list before this one. + * + * @return the previous node + */ + AVLNode previous() { + if (leftIsPrevious || left == null) { + return left; + } + return left.max(); + } + + /** + * Inserts a node at the position index. + * + * @param index is the index of the position relative to the position of + * the parent node. + * @param obj is the object to be stored in the position. + */ + AVLNode insert(final int index, final E obj) { + final int indexRelativeToMe = index - relativePosition; + + if (indexRelativeToMe <= 0) { + return insertOnLeft(indexRelativeToMe, obj); + } + return insertOnRight(indexRelativeToMe, obj); + } + + private AVLNode insertOnLeft(final int indexRelativeToMe, final E obj) { + if (getLeftSubTree() == null) { + setLeft(new AVLNode(-1, obj, this, left), null); + } else { + setLeft(left.insert(indexRelativeToMe, obj), null); + } + + if (relativePosition >= 0) { + relativePosition++; + } + final AVLNode ret = balance(); + recalcHeight(); + return ret; + } + + private AVLNode insertOnRight(final int indexRelativeToMe, final E obj) { + if (getRightSubTree() == null) { + setRight(new AVLNode(+1, obj, right, this), null); + } else { + setRight(right.insert(indexRelativeToMe, obj), null); + } + if (relativePosition < 0) { + relativePosition--; + } + final AVLNode ret = balance(); + recalcHeight(); + return ret; + } + + //----------------------------------------------------------------------- + /** + * Gets the left node, returning null if its a faedelung. + */ + private AVLNode getLeftSubTree() { + return leftIsPrevious ? null : left; + } + + /** + * Gets the right node, returning null if its a faedelung. + */ + private AVLNode getRightSubTree() { + return rightIsNext ? null : right; + } + + /** + * Gets the rightmost child of this node. + * + * @return the rightmost child (greatest index) + */ + private AVLNode max() { + return getRightSubTree() == null ? this : right.max(); + } + + /** + * Gets the leftmost child of this node. + * + * @return the leftmost child (smallest index) + */ + private AVLNode min() { + return getLeftSubTree() == null ? this : left.min(); + } + + /** + * Removes the node at a given position. + * + * @param index is the index of the element to be removed relative to the position of + * the parent node of the current node. + */ + AVLNode remove(final int index) { + final int indexRelativeToMe = index - relativePosition; + + if (indexRelativeToMe == 0) { + return removeSelf(); + } + if (indexRelativeToMe > 0) { + setRight(right.remove(indexRelativeToMe), right.right); + if (relativePosition < 0) { + relativePosition++; + } + } else { + setLeft(left.remove(indexRelativeToMe), left.left); + if (relativePosition > 0) { + relativePosition--; + } + } + recalcHeight(); + return balance(); + } + + private AVLNode removeMax() { + if (getRightSubTree() == null) { + return removeSelf(); + } + setRight(right.removeMax(), right.right); + if (relativePosition < 0) { + relativePosition++; + } + recalcHeight(); + return balance(); + } + + private AVLNode removeMin() { + if (getLeftSubTree() == null) { + return removeSelf(); + } + setLeft(left.removeMin(), left.left); + if (relativePosition > 0) { + relativePosition--; + } + recalcHeight(); + return balance(); + } + + /** + * Removes this node from the tree. + * + * @return the node that replaces this one in the parent + */ + private AVLNode removeSelf() { + if (getRightSubTree() == null && getLeftSubTree() == null) { + return null; + } + if (getRightSubTree() == null) { + if (relativePosition > 0) { + left.relativePosition += relativePosition + (relativePosition > 0 ? 0 : 1); + } + left.max().setRight(null, right); + return left; + } + if (getLeftSubTree() == null) { + right.relativePosition += relativePosition - (relativePosition < 0 ? 0 : 1); + right.min().setLeft(null, left); + return right; + } + + if (heightRightMinusLeft() > 0) { + // more on the right, so delete from the right + final AVLNode rightMin = right.min(); + value = rightMin.value; + if (leftIsPrevious) { + left = rightMin.left; + } + right = right.removeMin(); + if (relativePosition < 0) { + relativePosition++; + } + } else { + // more on the left or equal, so delete from the left + final AVLNode leftMax = left.max(); + value = leftMax.value; + if (rightIsNext) { + right = leftMax.right; + } + final AVLNode leftPrevious = left.left; + left = left.removeMax(); + if (left == null) { + // special case where left that was deleted was a double link + // only occurs when height difference is equal + left = leftPrevious; + leftIsPrevious = true; + } + if (relativePosition > 0) { + relativePosition--; + } + } + recalcHeight(); + return this; + } + + //----------------------------------------------------------------------- + /** + * Balances according to the AVL algorithm. + */ + private AVLNode balance() { + switch (heightRightMinusLeft()) { + case 1 : + case 0 : + case -1 : + return this; + case -2 : + if (left.heightRightMinusLeft() > 0) { + setLeft(left.rotateLeft(), null); + } + return rotateRight(); + case 2 : + if (right.heightRightMinusLeft() < 0) { + setRight(right.rotateRight(), null); + } + return rotateLeft(); + default : + throw new RuntimeException("tree inconsistent!"); + } + } + + /** + * Gets the relative position. + */ + private int getOffset(final AVLNode node) { + if (node == null) { + return 0; + } + return node.relativePosition; + } + + /** + * Sets the relative position. + */ + private int setOffset(final AVLNode node, final int newOffest) { + if (node == null) { + return 0; + } + final int oldOffset = getOffset(node); + node.relativePosition = newOffest; + return oldOffset; + } + + /** + * Sets the height by calculation. + */ + private void recalcHeight() { + height = Math.max( + getLeftSubTree() == null ? -1 : getLeftSubTree().height, + getRightSubTree() == null ? -1 : getRightSubTree().height) + 1; + } + + /** + * Returns the height of the node or -1 if the node is null. + */ + private int getHeight(final AVLNode node) { + return node == null ? -1 : node.height; + } + + /** + * Returns the height difference right - left + */ + private int heightRightMinusLeft() { + return getHeight(getRightSubTree()) - getHeight(getLeftSubTree()); + } + + private AVLNode rotateLeft() { + final AVLNode newTop = right; // can't be faedelung! + final AVLNode movedNode = getRightSubTree().getLeftSubTree(); + + final int newTopPosition = relativePosition + getOffset(newTop); + final int myNewPosition = -newTop.relativePosition; + final int movedPosition = getOffset(newTop) + getOffset(movedNode); + + setRight(movedNode, newTop); + newTop.setLeft(this, null); + + setOffset(newTop, newTopPosition); + setOffset(this, myNewPosition); + setOffset(movedNode, movedPosition); + return newTop; + } + + private AVLNode rotateRight() { + final AVLNode newTop = left; // can't be faedelung + final AVLNode movedNode = getLeftSubTree().getRightSubTree(); + + final int newTopPosition = relativePosition + getOffset(newTop); + final int myNewPosition = -newTop.relativePosition; + final int movedPosition = getOffset(newTop) + getOffset(movedNode); + + setLeft(movedNode, newTop); + newTop.setRight(this, null); + + setOffset(newTop, newTopPosition); + setOffset(this, myNewPosition); + setOffset(movedNode, movedPosition); + return newTop; + } + + /** + * Sets the left field to the node, or the previous node if that is null + * + * @param node the new left subtree node + * @param previous the previous node in the linked list + */ + private void setLeft(final AVLNode node, final AVLNode previous) { + leftIsPrevious = node == null; + left = leftIsPrevious ? previous : node; + recalcHeight(); + } + + /** + * Sets the right field to the node, or the next node if that is null + * + * @param node the new left subtree node + * @param next the next node in the linked list + */ + private void setRight(final AVLNode node, final AVLNode next) { + rightIsNext = node == null; + right = rightIsNext ? next : node; + recalcHeight(); + } + + /** + * Appends the elements of another tree list to this tree list by efficiently + * merging the two AVL trees. This operation is destructive to both trees and + * runs in O(log(m + n)) time. + * + * @param otherTree + * the root of the AVL tree to merge with this one + * @param currentSize + * the number of elements in this AVL tree + * @return the root of the new, merged AVL tree + */ + private AVLNode addAll(AVLNode otherTree, final int currentSize) { + final AVLNode maxNode = max(); + final AVLNode otherTreeMin = otherTree.min(); + + // We need to efficiently merge the two AVL trees while keeping them + // balanced (or nearly balanced). To do this, we take the shorter + // tree and combine it with a similar-height subtree of the taller + // tree. There are two symmetric cases: + // * this tree is taller, or + // * otherTree is taller. + if (otherTree.height > height) { + // CASE 1: The other tree is taller than this one. We will thus + // merge this tree into otherTree. + + // STEP 1: Remove the maximum element from this tree. + final AVLNode leftSubTree = removeMax(); + + // STEP 2: Navigate left from the root of otherTree until we + // find a subtree, s, that is no taller than me. (While we are + // navigating left, we store the nodes we encounter in a stack + // so that we can re-balance them in step 4.) + final Deque> sAncestors = new ArrayDeque>(); + AVLNode s = otherTree; + int sAbsolutePosition = s.relativePosition + currentSize; + int sParentAbsolutePosition = 0; + while (s != null && s.height > getHeight(leftSubTree)) { + sParentAbsolutePosition = sAbsolutePosition; + sAncestors.push(s); + s = s.left; + if (s != null) { + sAbsolutePosition += s.relativePosition; + } + } + + // STEP 3: Replace s with a newly constructed subtree whose root + // is maxNode, whose left subtree is leftSubTree, and whose right + // subtree is s. + maxNode.setLeft(leftSubTree, null); + maxNode.setRight(s, otherTreeMin); + if (leftSubTree != null) { + leftSubTree.max().setRight(null, maxNode); + leftSubTree.relativePosition -= currentSize - 1; + } + if (s != null) { + s.min().setLeft(null, maxNode); + s.relativePosition = sAbsolutePosition - currentSize + 1; + } + maxNode.relativePosition = currentSize - 1 - sParentAbsolutePosition; + otherTree.relativePosition += currentSize; + + // STEP 4: Re-balance the tree and recalculate the heights of s's ancestors. + s = maxNode; + while (!sAncestors.isEmpty()) { + final AVLNode sAncestor = sAncestors.pop(); + sAncestor.setLeft(s, null); + s = sAncestor.balance(); + } + return s; + } + otherTree = otherTree.removeMin(); + + final Deque> sAncestors = new ArrayDeque>(); + AVLNode s = this; + int sAbsolutePosition = s.relativePosition; + int sParentAbsolutePosition = 0; + while (s != null && s.height > getHeight(otherTree)) { + sParentAbsolutePosition = sAbsolutePosition; + sAncestors.push(s); + s = s.right; + if (s != null) { + sAbsolutePosition += s.relativePosition; + } + } + + otherTreeMin.setRight(otherTree, null); + otherTreeMin.setLeft(s, maxNode); + if (otherTree != null) { + otherTree.min().setLeft(null, otherTreeMin); + otherTree.relativePosition++; + } + if (s != null) { + s.max().setRight(null, otherTreeMin); + s.relativePosition = sAbsolutePosition - currentSize; + } + otherTreeMin.relativePosition = currentSize - sParentAbsolutePosition; + + s = otherTreeMin; + while (!sAncestors.isEmpty()) { + final AVLNode sAncestor = sAncestors.pop(); + sAncestor.setRight(s, null); + s = sAncestor.balance(); + } + return s; + } + +// private void checkFaedelung() { +// AVLNode maxNode = left.max(); +// if (!maxNode.rightIsFaedelung || maxNode.right != this) { +// throw new RuntimeException(maxNode + " should right-faedel to " + this); +// } +// AVLNode minNode = right.min(); +// if (!minNode.leftIsFaedelung || minNode.left != this) { +// throw new RuntimeException(maxNode + " should left-faedel to " + this); +// } +// } +// +// private int checkTreeDepth() { +// int hright = (getRightSubTree() == null ? -1 : getRightSubTree().checkTreeDepth()); +// // System.out.print("checkTreeDepth"); +// // System.out.print(this); +// // System.out.print(" left: "); +// // System.out.print(_left); +// // System.out.print(" right: "); +// // System.out.println(_right); +// +// int hleft = (left == null ? -1 : left.checkTreeDepth()); +// if (height != Math.max(hright, hleft) + 1) { +// throw new RuntimeException( +// "height should be max" + hleft + "," + hright + " but is " + height); +// } +// return height; +// } +// +// private int checkLeftSubNode() { +// if (getLeftSubTree() == null) { +// return 0; +// } +// int count = 1 + left.checkRightSubNode(); +// if (left.relativePosition != -count) { +// throw new RuntimeException(); +// } +// return count + left.checkLeftSubNode(); +// } +// +// private int checkRightSubNode() { +// AVLNode right = getRightSubTree(); +// if (right == null) { +// return 0; +// } +// int count = 1; +// count += right.checkLeftSubNode(); +// if (right.relativePosition != count) { +// throw new RuntimeException(); +// } +// return count + right.checkRightSubNode(); +// } + + /** + * Used for debugging. + */ + @Override + public String toString() { + return new StringBuilder() + .append("AVLNode(") + .append(relativePosition) + .append(',') + .append(left != null) + .append(',') + .append(value) + .append(',') + .append(getRightSubTree() != null) + .append(", faedelung ") + .append(rightIsNext) + .append(" )") + .toString(); + } + } + + /** + * A list iterator over the linked list. + */ + static class TreeListIterator implements ListIterator, OrderedIterator { + /** The parent list */ + private final TreeList parent; + /** + * Cache of the next node that will be returned by {@link #next()}. + */ + private AVLNode next; + /** + * The index of the next node to be returned. + */ + private int nextIndex; + /** + * Cache of the last node that was returned by {@link #next()} + * or {@link #previous()}. + */ + private AVLNode current; + /** + * The index of the last node that was returned. + */ + private int currentIndex; + /** + * The modification count that the list is expected to have. If the list + * doesn't have this count, then a + * {@link java.util.ConcurrentModificationException} may be thrown by + * the operations. + */ + private int expectedModCount; + + /** + * Create a ListIterator for a list. + * + * @param parent the parent list + * @param fromIndex the index to start at + */ + protected TreeListIterator(final TreeList parent, final int fromIndex) throws IndexOutOfBoundsException { + super(); + this.parent = parent; + this.expectedModCount = parent.modCount; + this.next = parent.root == null ? null : parent.root.get(fromIndex); + this.nextIndex = fromIndex; + this.currentIndex = -1; + } + + /** + * Checks the modification count of the list is the value that this + * object expects. + * + * @throws ConcurrentModificationException If the list's modification + * count isn't the value that was expected. + */ + protected void checkModCount() { + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + + public boolean hasNext() { + return nextIndex < parent.size(); + } + + public E next() { + checkModCount(); + if (!hasNext()) { + throw new NoSuchElementException("No element at index " + nextIndex + "."); + } + if (next == null) { + next = parent.root.get(nextIndex); + } + final E value = next.getValue(); + current = next; + currentIndex = nextIndex++; + next = next.next(); + return value; + } + + public boolean hasPrevious() { + return nextIndex > 0; + } + + public E previous() { + checkModCount(); + if (!hasPrevious()) { + throw new NoSuchElementException("Already at start of list."); + } + if (next == null) { + next = parent.root.get(nextIndex - 1); + } else { + next = next.previous(); + } + final E value = next.getValue(); + current = next; + currentIndex = --nextIndex; + return value; + } + + public int nextIndex() { + return nextIndex; + } + + public int previousIndex() { + return nextIndex() - 1; + } + + public void remove() { + checkModCount(); + if (currentIndex == -1) { + throw new IllegalStateException(); + } + parent.remove(currentIndex); + if (nextIndex != currentIndex) { + // remove() following next() + nextIndex--; + } + // the AVL node referenced by next may have become stale after a remove + // reset it now: will be retrieved by next call to next()/previous() via nextIndex + next = null; + current = null; + currentIndex = -1; + expectedModCount++; + } + + public void set(final E obj) { + checkModCount(); + if (current == null) { + throw new IllegalStateException(); + } + current.setValue(obj); + } + + public void add(final E obj) { + checkModCount(); + parent.add(nextIndex, obj); + current = null; + currentIndex = -1; + nextIndex++; + expectedModCount++; + } + } + +} diff --git a/src/org/apache/commons/collections4/list/UnmodifiableList.java b/src/org/apache/commons/collections4/list/UnmodifiableList.java new file mode 100644 index 0000000..d8ff163 --- /dev/null +++ b/src/org/apache/commons/collections4/list/UnmodifiableList.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.list; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; +import org.apache.commons.collections4.iterators.UnmodifiableListIterator; + +/** + * Decorates another List to ensure it can't be altered. + *

              + * This class is Serializable from Commons Collections 3.1. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableList.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableList + extends AbstractSerializableListDecorator + implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = 6595182819922443652L; + + /** + * Factory method to create an unmodifiable list. + * + * @param the type of the elements in the list + * @param list the list to decorate, must not be null + * @return a new unmodifiable list + * @throws NullPointerException if list is null + * @since 4.0 + */ + public static List unmodifiableList(final List list) { + if (list instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final List tmpList = (List) list; + return tmpList; + } + return new UnmodifiableList(list); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param list the list to decorate, must not be null + * @throws NullPointerException if list is null + */ + @SuppressWarnings("unchecked") // safe to upcast + public UnmodifiableList(final List list) { + super((List) list); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public ListIterator listIterator() { + return UnmodifiableListIterator.umodifiableListIterator(decorated().listIterator()); + } + + @Override + public ListIterator listIterator(final int index) { + return UnmodifiableListIterator.umodifiableListIterator(decorated().listIterator(index)); + } + + @Override + public void add(final int index, final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final int index, final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public E remove(final int index) { + throw new UnsupportedOperationException(); + } + + @Override + public E set(final int index, final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public List subList(final int fromIndex, final int toIndex) { + final List sub = decorated().subList(fromIndex, toIndex); + return new UnmodifiableList(sub); + } + +} diff --git a/src/org/apache/commons/collections4/list/package-info.java b/src/org/apache/commons/collections4/list/package-info.java new file mode 100644 index 0000000..133e80d --- /dev/null +++ b/src/org/apache/commons/collections4/list/package-info.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the {@link java.util.List List} interface. + *

              + * The following implementations are provided in the package: + *

                + *
              • TreeList - a list that is optimised for insertions and removals at any index in the list
              • + *
              • CursorableLinkedList - a list that can be modified while the listIterator (cursor) is being used
              • + *
              • NodeCachingLinkedList - a linked list that caches the storage nodes for a performance gain
              • + *
              + *

              + * The following decorators are provided in the package: + *

                + *
              • Unmodifiable - ensures the collection cannot be altered
              • + *
              • Predicated - ensures that only elements that are valid according to a predicate can be added
              • + *
              • Transformed - transforms each element added
              • + *
              • FixedSize - ensures that the size of the list cannot change
              • + *
              • Lazy - creates objects in the list on demand
              • + *
              • Growth - grows the list instead of erroring when set/add used with index beyond the list size
              • + *
              • SetUnique - a list that avoids duplicate entries like a Set
              • + *
              + * + * @version $Id: package-info.java 1469004 2013-04-17 17:37:03Z tn $ + */ +package org.apache.commons.collections4.list; diff --git a/src/org/apache/commons/collections4/map/AbstractHashedMap.java b/src/org/apache/commons/collections4/map/AbstractHashedMap.java new file mode 100644 index 0000000..a111c48 --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractHashedMap.java @@ -0,0 +1,1389 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.AbstractCollection; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.apache.commons.collections4.IterableMap; +import org.apache.commons.collections4.KeyValue; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.iterators.EmptyIterator; +import org.apache.commons.collections4.iterators.EmptyMapIterator; + +/** + * An abstract implementation of a hash-based map which provides numerous points for + * subclasses to override. + *

              + * This class implements all the features necessary for a subclass hash-based map. + * Key-value entries are stored in instances of the HashEntry class, + * which can be overridden and replaced. The iterators can similarly be replaced, + * without the need to replace the KeySet, EntrySet and Values view classes. + *

              + * Overridable methods are provided to change the default hashing behaviour, and + * to change how entries are added to and removed from the map. Hopefully, all you + * need for unusual subclasses is here. + *

              + * NOTE: From Commons Collections 3.1 this class extends AbstractMap. + * This is to provide backwards compatibility for ReferenceMap between v3.0 and v3.1. + * This extends clause will be removed in v5.0. + * + * @since 3.0 + * @version $Id: AbstractHashedMap.java 1649010 2015-01-02 12:32:37Z tn $ + */ +public class AbstractHashedMap extends AbstractMap implements IterableMap { + + protected static final String NO_NEXT_ENTRY = "No next() entry in the iteration"; + protected static final String NO_PREVIOUS_ENTRY = "No previous() entry in the iteration"; + protected static final String REMOVE_INVALID = "remove() can only be called once after next()"; + protected static final String GETKEY_INVALID = "getKey() can only be called after next() and before remove()"; + protected static final String GETVALUE_INVALID = "getValue() can only be called after next() and before remove()"; + protected static final String SETVALUE_INVALID = "setValue() can only be called after next() and before remove()"; + + /** The default capacity to use */ + protected static final int DEFAULT_CAPACITY = 16; + /** The default threshold to use */ + protected static final int DEFAULT_THRESHOLD = 12; + /** The default load factor to use */ + protected static final float DEFAULT_LOAD_FACTOR = 0.75f; + /** The maximum capacity allowed */ + protected static final int MAXIMUM_CAPACITY = 1 << 30; + /** An object for masking null */ + protected static final Object NULL = new Object(); + + /** Load factor, normally 0.75 */ + transient float loadFactor; + /** The size of the map */ + transient int size; + /** Map entries */ + transient HashEntry[] data; + /** Size at which to rehash */ + transient int threshold; + /** Modification count for iterators */ + transient int modCount; + /** Entry set */ + transient EntrySet entrySet; + /** Key set */ + transient KeySet keySet; + /** Values */ + transient Values values; + + /** + * Constructor only used in deserialization, do not use otherwise. + */ + protected AbstractHashedMap() { + super(); + } + + /** + * Constructor which performs no validation on the passed in parameters. + * + * @param initialCapacity the initial capacity, must be a power of two + * @param loadFactor the load factor, must be > 0.0f and generally < 1.0f + * @param threshold the threshold, must be sensible + */ + @SuppressWarnings("unchecked") + protected AbstractHashedMap(final int initialCapacity, final float loadFactor, final int threshold) { + super(); + this.loadFactor = loadFactor; + this.data = new HashEntry[initialCapacity]; + this.threshold = threshold; + init(); + } + + /** + * Constructs a new, empty map with the specified initial capacity and + * default load factor. + * + * @param initialCapacity the initial capacity + * @throws IllegalArgumentException if the initial capacity is negative + */ + protected AbstractHashedMap(final int initialCapacity) { + this(initialCapacity, DEFAULT_LOAD_FACTOR); + } + + /** + * Constructs a new, empty map with the specified initial capacity and + * load factor. + * + * @param initialCapacity the initial capacity + * @param loadFactor the load factor + * @throws IllegalArgumentException if the initial capacity is negative + * @throws IllegalArgumentException if the load factor is less than or equal to zero + */ + @SuppressWarnings("unchecked") + protected AbstractHashedMap(int initialCapacity, final float loadFactor) { + super(); + if (initialCapacity < 0) { + throw new IllegalArgumentException("Initial capacity must be a non negative number"); + } + if (loadFactor <= 0.0f || Float.isNaN(loadFactor)) { + throw new IllegalArgumentException("Load factor must be greater than 0"); + } + this.loadFactor = loadFactor; + initialCapacity = calculateNewCapacity(initialCapacity); + this.threshold = calculateThreshold(initialCapacity, loadFactor); + this.data = new HashEntry[initialCapacity]; + init(); + } + + /** + * Constructor copying elements from another map. + * + * @param map the map to copy + * @throws NullPointerException if the map is null + */ + protected AbstractHashedMap(final Map map) { + this(Math.max(2 * map.size(), DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR); + _putAll(map); + } + + /** + * Initialise subclasses during construction, cloning or deserialization. + */ + protected void init() { + } + + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the key specified. + * + * @param key the key + * @return the mapped value, null if no match + */ + @Override + public V get(Object key) { + key = convertKey(key); + final int hashCode = hash(key); + HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { + return entry.getValue(); + } + entry = entry.next; + } + return null; + } + + /** + * Gets the size of the map. + * + * @return the size + */ + @Override + public int size() { + return size; + } + + /** + * Checks whether the map is currently empty. + * + * @return true if the map is currently size zero + */ + @Override + public boolean isEmpty() { + return size == 0; + } + + //----------------------------------------------------------------------- + /** + * Checks whether the map contains the specified key. + * + * @param key the key to search for + * @return true if the map contains the key + */ + @Override + public boolean containsKey(Object key) { + key = convertKey(key); + final int hashCode = hash(key); + HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { + return true; + } + entry = entry.next; + } + return false; + } + + /** + * Checks whether the map contains the specified value. + * + * @param value the value to search for + * @return true if the map contains the value + */ + @Override + public boolean containsValue(final Object value) { + if (value == null) { + for (final HashEntry element : data) { + HashEntry entry = element; + while (entry != null) { + if (entry.getValue() == null) { + return true; + } + entry = entry.next; + } + } + } else { + for (final HashEntry element : data) { + HashEntry entry = element; + while (entry != null) { + if (isEqualValue(value, entry.getValue())) { + return true; + } + entry = entry.next; + } + } + } + return false; + } + + //----------------------------------------------------------------------- + /** + * Puts a key-value mapping into this map. + * + * @param key the key to add + * @param value the value to add + * @return the value previously mapped to this key, null if none + */ + @Override + public V put(final K key, final V value) { + final Object convertedKey = convertKey(key); + final int hashCode = hash(convertedKey); + final int index = hashIndex(hashCode, data.length); + HashEntry entry = data[index]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(convertedKey, entry.key)) { + final V oldValue = entry.getValue(); + updateEntry(entry, value); + return oldValue; + } + entry = entry.next; + } + + addMapping(index, hashCode, key, value); + return null; + } + + /** + * Puts all the values from the specified map into this map. + *

              + * This implementation iterates around the specified map and + * uses {@link #put(Object, Object)}. + * + * @param map the map to add + * @throws NullPointerException if the map is null + */ + @Override + public void putAll(final Map map) { + _putAll(map); + } + + /** + * Puts all the values from the specified map into this map. + *

              + * This implementation iterates around the specified map and + * uses {@link #put(Object, Object)}. + *

              + * It is private to allow the constructor to still call it + * even when putAll is overriden. + * + * @param map the map to add + * @throws NullPointerException if the map is null + */ + private void _putAll(final Map map) { + final int mapSize = map.size(); + if (mapSize == 0) { + return; + } + final int newSize = (int) ((size + mapSize) / loadFactor + 1); + ensureCapacity(calculateNewCapacity(newSize)); + for (final Map.Entry entry: map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + /** + * Removes the specified mapping from this map. + * + * @param key the mapping to remove + * @return the value mapped to the removed key, null if key not in map + */ + @Override + public V remove(Object key) { + key = convertKey(key); + final int hashCode = hash(key); + final int index = hashIndex(hashCode, data.length); + HashEntry entry = data[index]; + HashEntry previous = null; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { + final V oldValue = entry.getValue(); + removeMapping(entry, index, previous); + return oldValue; + } + previous = entry; + entry = entry.next; + } + return null; + } + + /** + * Clears the map, resetting the size to zero and nullifying references + * to avoid garbage collection issues. + */ + @Override + public void clear() { + modCount++; + final HashEntry[] data = this.data; + for (int i = data.length - 1; i >= 0; i--) { + data[i] = null; + } + size = 0; + } + + //----------------------------------------------------------------------- + /** + * Converts input keys to another object for storage in the map. + * This implementation masks nulls. + * Subclasses can override this to perform alternate key conversions. + *

              + * The reverse conversion can be changed, if required, by overriding the + * getKey() method in the hash entry. + * + * @param key the key convert + * @return the converted key + */ + protected Object convertKey(final Object key) { + return key == null ? NULL : key; + } + + /** + * Gets the hash code for the key specified. + * This implementation uses the additional hashing routine from JDK1.4. + * Subclasses can override this to return alternate hash codes. + * + * @param key the key to get a hash code for + * @return the hash code + */ + protected int hash(final Object key) { + // same as JDK 1.4 + int h = key.hashCode(); + h += ~(h << 9); + h ^= h >>> 14; + h += h << 4; + h ^= h >>> 10; + return h; + } + + /** + * Compares two keys, in internal converted form, to see if they are equal. + * This implementation uses the equals method and assumes neither key is null. + * Subclasses can override this to match differently. + * + * @param key1 the first key to compare passed in from outside + * @param key2 the second key extracted from the entry via entry.key + * @return true if equal + */ + protected boolean isEqualKey(final Object key1, final Object key2) { + return key1 == key2 || key1.equals(key2); + } + + /** + * Compares two values, in external form, to see if they are equal. + * This implementation uses the equals method and assumes neither value is null. + * Subclasses can override this to match differently. + * + * @param value1 the first value to compare passed in from outside + * @param value2 the second value extracted from the entry via getValue() + * @return true if equal + */ + protected boolean isEqualValue(final Object value1, final Object value2) { + return value1 == value2 || value1.equals(value2); + } + + /** + * Gets the index into the data storage for the hashCode specified. + * This implementation uses the least significant bits of the hashCode. + * Subclasses can override this to return alternate bucketing. + * + * @param hashCode the hash code to use + * @param dataSize the size of the data to pick a bucket from + * @return the bucket index + */ + protected int hashIndex(final int hashCode, final int dataSize) { + return hashCode & dataSize - 1; + } + + //----------------------------------------------------------------------- + /** + * Gets the entry mapped to the key specified. + *

              + * This method exists for subclasses that may need to perform a multi-step + * process accessing the entry. The public methods in this class don't use this + * method to gain a small performance boost. + * + * @param key the key + * @return the entry, null if no match + */ + protected HashEntry getEntry(Object key) { + key = convertKey(key); + final int hashCode = hash(key); + HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { + return entry; + } + entry = entry.next; + } + return null; + } + + //----------------------------------------------------------------------- + /** + * Updates an existing key-value mapping to change the value. + *

              + * This implementation calls setValue() on the entry. + * Subclasses could override to handle changes to the map. + * + * @param entry the entry to update + * @param newValue the new value to store + */ + protected void updateEntry(final HashEntry entry, final V newValue) { + entry.setValue(newValue); + } + + /** + * Reuses an existing key-value mapping, storing completely new data. + *

              + * This implementation sets all the data fields on the entry. + * Subclasses could populate additional entry fields. + * + * @param entry the entry to update, not null + * @param hashIndex the index in the data array + * @param hashCode the hash code of the key to add + * @param key the key to add + * @param value the value to add + */ + protected void reuseEntry(final HashEntry entry, final int hashIndex, final int hashCode, + final K key, final V value) { + entry.next = data[hashIndex]; + entry.hashCode = hashCode; + entry.key = key; + entry.value = value; + } + + //----------------------------------------------------------------------- + /** + * Adds a new key-value mapping into this map. + *

              + * This implementation calls createEntry(), addEntry() + * and checkCapacity(). + * It also handles changes to modCount and size. + * Subclasses could override to fully control adds to the map. + * + * @param hashIndex the index into the data array to store at + * @param hashCode the hash code of the key to add + * @param key the key to add + * @param value the value to add + */ + protected void addMapping(final int hashIndex, final int hashCode, final K key, final V value) { + modCount++; + final HashEntry entry = createEntry(data[hashIndex], hashCode, key, value); + addEntry(entry, hashIndex); + size++; + checkCapacity(); + } + + /** + * Creates an entry to store the key-value data. + *

              + * This implementation creates a new HashEntry instance. + * Subclasses can override this to return a different storage class, + * or implement caching. + * + * @param next the next entry in sequence + * @param hashCode the hash code to use + * @param key the key to store + * @param value the value to store + * @return the newly created entry + */ + protected HashEntry createEntry(final HashEntry next, final int hashCode, final K key, final V value) { + return new HashEntry(next, hashCode, convertKey(key), value); + } + + /** + * Adds an entry into this map. + *

              + * This implementation adds the entry to the data storage table. + * Subclasses could override to handle changes to the map. + * + * @param entry the entry to add + * @param hashIndex the index into the data array to store at + */ + protected void addEntry(final HashEntry entry, final int hashIndex) { + data[hashIndex] = entry; + } + + //----------------------------------------------------------------------- + /** + * Removes a mapping from the map. + *

              + * This implementation calls removeEntry() and destroyEntry(). + * It also handles changes to modCount and size. + * Subclasses could override to fully control removals from the map. + * + * @param entry the entry to remove + * @param hashIndex the index into the data structure + * @param previous the previous entry in the chain + */ + protected void removeMapping(final HashEntry entry, final int hashIndex, final HashEntry previous) { + modCount++; + removeEntry(entry, hashIndex, previous); + size--; + destroyEntry(entry); + } + + /** + * Removes an entry from the chain stored in a particular index. + *

              + * This implementation removes the entry from the data storage table. + * The size is not updated. + * Subclasses could override to handle changes to the map. + * + * @param entry the entry to remove + * @param hashIndex the index into the data structure + * @param previous the previous entry in the chain + */ + protected void removeEntry(final HashEntry entry, final int hashIndex, final HashEntry previous) { + if (previous == null) { + data[hashIndex] = entry.next; + } else { + previous.next = entry.next; + } + } + + /** + * Kills an entry ready for the garbage collector. + *

              + * This implementation prepares the HashEntry for garbage collection. + * Subclasses can override this to implement caching (override clear as well). + * + * @param entry the entry to destroy + */ + protected void destroyEntry(final HashEntry entry) { + entry.next = null; + entry.key = null; + entry.value = null; + } + + //----------------------------------------------------------------------- + /** + * Checks the capacity of the map and enlarges it if necessary. + *

              + * This implementation uses the threshold to check if the map needs enlarging + */ + protected void checkCapacity() { + if (size >= threshold) { + final int newCapacity = data.length * 2; + if (newCapacity <= MAXIMUM_CAPACITY) { + ensureCapacity(newCapacity); + } + } + } + + /** + * Changes the size of the data structure to the capacity proposed. + * + * @param newCapacity the new capacity of the array (a power of two, less or equal to max) + */ + @SuppressWarnings("unchecked") + protected void ensureCapacity(final int newCapacity) { + final int oldCapacity = data.length; + if (newCapacity <= oldCapacity) { + return; + } + if (size == 0) { + threshold = calculateThreshold(newCapacity, loadFactor); + data = new HashEntry[newCapacity]; + } else { + final HashEntry oldEntries[] = data; + final HashEntry newEntries[] = new HashEntry[newCapacity]; + + modCount++; + for (int i = oldCapacity - 1; i >= 0; i--) { + HashEntry entry = oldEntries[i]; + if (entry != null) { + oldEntries[i] = null; // gc + do { + final HashEntry next = entry.next; + final int index = hashIndex(entry.hashCode, newCapacity); + entry.next = newEntries[index]; + newEntries[index] = entry; + entry = next; + } while (entry != null); + } + } + threshold = calculateThreshold(newCapacity, loadFactor); + data = newEntries; + } + } + + /** + * Calculates the new capacity of the map. + * This implementation normalizes the capacity to a power of two. + * + * @param proposedCapacity the proposed capacity + * @return the normalized new capacity + */ + protected int calculateNewCapacity(final int proposedCapacity) { + int newCapacity = 1; + if (proposedCapacity > MAXIMUM_CAPACITY) { + newCapacity = MAXIMUM_CAPACITY; + } else { + while (newCapacity < proposedCapacity) { + newCapacity <<= 1; // multiply by two + } + if (newCapacity > MAXIMUM_CAPACITY) { + newCapacity = MAXIMUM_CAPACITY; + } + } + return newCapacity; + } + + /** + * Calculates the new threshold of the map, where it will be resized. + * This implementation uses the load factor. + * + * @param newCapacity the new capacity + * @param factor the load factor + * @return the new resize threshold + */ + protected int calculateThreshold(final int newCapacity, final float factor) { + return (int) (newCapacity * factor); + } + + //----------------------------------------------------------------------- + /** + * Gets the next field from a HashEntry. + * Used in subclasses that have no visibility of the field. + * + * @param entry the entry to query, must not be null + * @return the next field of the entry + * @throws NullPointerException if the entry is null + * @since 3.1 + */ + protected HashEntry entryNext(final HashEntry entry) { + return entry.next; + } + + /** + * Gets the hashCode field from a HashEntry. + * Used in subclasses that have no visibility of the field. + * + * @param entry the entry to query, must not be null + * @return the hashCode field of the entry + * @throws NullPointerException if the entry is null + * @since 3.1 + */ + protected int entryHashCode(final HashEntry entry) { + return entry.hashCode; + } + + /** + * Gets the key field from a HashEntry. + * Used in subclasses that have no visibility of the field. + * + * @param entry the entry to query, must not be null + * @return the key field of the entry + * @throws NullPointerException if the entry is null + * @since 3.1 + */ + protected K entryKey(final HashEntry entry) { + return entry.getKey(); + } + + /** + * Gets the value field from a HashEntry. + * Used in subclasses that have no visibility of the field. + * + * @param entry the entry to query, must not be null + * @return the value field of the entry + * @throws NullPointerException if the entry is null + * @since 3.1 + */ + protected V entryValue(final HashEntry entry) { + return entry.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets an iterator over the map. + * Changes made to the iterator affect this map. + *

              + * A MapIterator returns the keys in the map. It also provides convenient + * methods to get the key and value, and set the value. + * It avoids the need to create an entrySet/keySet/values object. + * It also avoids creating the Map.Entry object. + * + * @return the map iterator + */ + public MapIterator mapIterator() { + if (size == 0) { + return EmptyMapIterator.emptyMapIterator(); + } + return new HashMapIterator(this); + } + + /** + * MapIterator implementation. + */ + protected static class HashMapIterator extends HashIterator implements MapIterator { + + protected HashMapIterator(final AbstractHashedMap parent) { + super(parent); + } + + public K next() { + return super.nextEntry().getKey(); + } + + public K getKey() { + final HashEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID); + } + return current.getKey(); + } + + public V getValue() { + final HashEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID); + } + return current.getValue(); + } + + public V setValue(final V value) { + final HashEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID); + } + return current.setValue(value); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the entrySet view of the map. + * Changes made to the view affect this map. + * To simply iterate through the entries, use {@link #mapIterator()}. + * + * @return the entrySet view + */ + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = new EntrySet(this); + } + return entrySet; + } + + /** + * Creates an entry set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the entrySet iterator + */ + protected Iterator> createEntrySetIterator() { + if (size() == 0) { + return EmptyIterator.>emptyIterator(); + } + return new EntrySetIterator(this); + } + + /** + * EntrySet implementation. + */ + protected static class EntrySet extends AbstractSet> { + /** The parent map */ + private final AbstractHashedMap parent; + + protected EntrySet(final AbstractHashedMap parent) { + super(); + this.parent = parent; + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public void clear() { + parent.clear(); + } + + @Override + public boolean contains(final Object entry) { + if (entry instanceof Map.Entry) { + final Map.Entry e = (Map.Entry) entry; + final Entry match = parent.getEntry(e.getKey()); + return match != null && match.equals(e); + } + return false; + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + if (contains(obj) == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + parent.remove(entry.getKey()); + return true; + } + + @Override + public Iterator> iterator() { + return parent.createEntrySetIterator(); + } + } + + /** + * EntrySet iterator. + */ + protected static class EntrySetIterator extends HashIterator implements Iterator> { + + protected EntrySetIterator(final AbstractHashedMap parent) { + super(parent); + } + + public Map.Entry next() { + return super.nextEntry(); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the keySet view of the map. + * Changes made to the view affect this map. + * To simply iterate through the keys, use {@link #mapIterator()}. + * + * @return the keySet view + */ + @Override + public Set keySet() { + if (keySet == null) { + keySet = new KeySet(this); + } + return keySet; + } + + /** + * Creates a key set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the keySet iterator + */ + protected Iterator createKeySetIterator() { + if (size() == 0) { + return EmptyIterator.emptyIterator(); + } + return new KeySetIterator(this); + } + + /** + * KeySet implementation. + */ + protected static class KeySet extends AbstractSet { + /** The parent map */ + private final AbstractHashedMap parent; + + protected KeySet(final AbstractHashedMap parent) { + super(); + this.parent = parent; + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public void clear() { + parent.clear(); + } + + @Override + public boolean contains(final Object key) { + return parent.containsKey(key); + } + + @Override + public boolean remove(final Object key) { + final boolean result = parent.containsKey(key); + parent.remove(key); + return result; + } + + @Override + public Iterator iterator() { + return parent.createKeySetIterator(); + } + } + + /** + * KeySet iterator. + */ + protected static class KeySetIterator extends HashIterator implements Iterator { + + @SuppressWarnings("unchecked") + protected KeySetIterator(final AbstractHashedMap parent) { + super((AbstractHashedMap) parent); + } + + public K next() { + return super.nextEntry().getKey(); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the values view of the map. + * Changes made to the view affect this map. + * To simply iterate through the values, use {@link #mapIterator()}. + * + * @return the values view + */ + @Override + public Collection values() { + if (values == null) { + values = new Values(this); + } + return values; + } + + /** + * Creates a values iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the values iterator + */ + protected Iterator createValuesIterator() { + if (size() == 0) { + return EmptyIterator.emptyIterator(); + } + return new ValuesIterator(this); + } + + /** + * Values implementation. + */ + protected static class Values extends AbstractCollection { + /** The parent map */ + private final AbstractHashedMap parent; + + protected Values(final AbstractHashedMap parent) { + super(); + this.parent = parent; + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public void clear() { + parent.clear(); + } + + @Override + public boolean contains(final Object value) { + return parent.containsValue(value); + } + + @Override + public Iterator iterator() { + return parent.createValuesIterator(); + } + } + + /** + * Values iterator. + */ + protected static class ValuesIterator extends HashIterator implements Iterator { + + @SuppressWarnings("unchecked") + protected ValuesIterator(final AbstractHashedMap parent) { + super((AbstractHashedMap) parent); + } + + public V next() { + return super.nextEntry().getValue(); + } + } + + //----------------------------------------------------------------------- + /** + * HashEntry used to store the data. + *

              + * If you subclass AbstractHashedMap but not HashEntry + * then you will not be able to access the protected fields. + * The entryXxx() methods on AbstractHashedMap exist + * to provide the necessary access. + */ + protected static class HashEntry implements Map.Entry, KeyValue { + /** The next entry in the hash chain */ + protected HashEntry next; + /** The hash code of the key */ + protected int hashCode; + /** The key */ + protected Object key; + /** The value */ + protected Object value; + + protected HashEntry(final HashEntry next, final int hashCode, final Object key, final V value) { + super(); + this.next = next; + this.hashCode = hashCode; + this.key = key; + this.value = value; + } + + @SuppressWarnings("unchecked") + public K getKey() { + if (key == NULL) { + return null; + } + return (K) key; + } + + @SuppressWarnings("unchecked") + public V getValue() { + return (V) value; + } + + @SuppressWarnings("unchecked") + public V setValue(final V value) { + final Object old = this.value; + this.value = value; + return (V) old; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry other = (Map.Entry) obj; + return + (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && + (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue())); + } + + @Override + public int hashCode() { + return (getKey() == null ? 0 : getKey().hashCode()) ^ + (getValue() == null ? 0 : getValue().hashCode()); + } + + @Override + public String toString() { + return new StringBuilder().append(getKey()).append('=').append(getValue()).toString(); + } + } + + /** + * Base Iterator + */ + protected static abstract class HashIterator { + + /** The parent map */ + private final AbstractHashedMap parent; + /** The current index into the array of buckets */ + private int hashIndex; + /** The last returned entry */ + private HashEntry last; + /** The next entry */ + private HashEntry next; + /** The modification count expected */ + private int expectedModCount; + + protected HashIterator(final AbstractHashedMap parent) { + super(); + this.parent = parent; + final HashEntry[] data = parent.data; + int i = data.length; + HashEntry next = null; + while (i > 0 && next == null) { + next = data[--i]; + } + this.next = next; + this.hashIndex = i; + this.expectedModCount = parent.modCount; + } + + public boolean hasNext() { + return next != null; + } + + protected HashEntry nextEntry() { + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + final HashEntry newCurrent = next; + if (newCurrent == null) { + throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY); + } + final HashEntry[] data = parent.data; + int i = hashIndex; + HashEntry n = newCurrent.next; + while (n == null && i > 0) { + n = data[--i]; + } + next = n; + hashIndex = i; + last = newCurrent; + return newCurrent; + } + + protected HashEntry currentEntry() { + return last; + } + + public void remove() { + if (last == null) { + throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID); + } + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + parent.remove(last.getKey()); + last = null; + expectedModCount = parent.modCount; + } + + @Override + public String toString() { + if (last != null) { + return "Iterator[" + last.getKey() + "=" + last.getValue() + "]"; + } + return "Iterator[]"; + } + } + + //----------------------------------------------------------------------- + /** + * Writes the map data to the stream. This method must be overridden if a + * subclass must be setup before put() is used. + *

              + * Serialization is not one of the JDK's nicest topics. Normal serialization will + * initialise the superclass before the subclass. Sometimes however, this isn't + * what you want, as in this case the put() method on read can be + * affected by subclass state. + *

              + * The solution adopted here is to serialize the state data of this class in + * this protected method. This method must be called by the + * writeObject() of the first serializable subclass. + *

              + * Subclasses may override if they have a specific field that must be present + * on read before this implementation will work. Generally, the read determines + * what must be serialized here, if anything. + * + * @param out the output stream + * @throws IOException if an error occurs while writing tothe stream + */ + protected void doWriteObject(final ObjectOutputStream out) throws IOException { + out.writeFloat(loadFactor); + out.writeInt(data.length); + out.writeInt(size); + for (final MapIterator it = mapIterator(); it.hasNext();) { + out.writeObject(it.next()); + out.writeObject(it.getValue()); + } + } + + /** + * Reads the map data from the stream. This method must be overridden if a + * subclass must be setup before put() is used. + *

              + * Serialization is not one of the JDK's nicest topics. Normal serialization will + * initialise the superclass before the subclass. Sometimes however, this isn't + * what you want, as in this case the put() method on read can be + * affected by subclass state. + *

              + * The solution adopted here is to deserialize the state data of this class in + * this protected method. This method must be called by the + * readObject() of the first serializable subclass. + *

              + * Subclasses may override if the subclass has a specific field that must be present + * before put() or calculateThreshold() will work correctly. + * + * @param in the input stream + * @throws IOException if an error occurs while reading from the stream + * @throws ClassNotFoundException if an object read from the stream can not be loaded + */ + @SuppressWarnings("unchecked") + protected void doReadObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + loadFactor = in.readFloat(); + final int capacity = in.readInt(); + final int size = in.readInt(); + init(); + threshold = calculateThreshold(capacity, loadFactor); + data = new HashEntry[capacity]; + for (int i = 0; i < size; i++) { + final K key = (K) in.readObject(); + final V value = (V) in.readObject(); + put(key, value); + } + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the keys or values. + *

              + * To implement clone(), a subclass must implement the + * Cloneable interface and make this method public. + * + * @return a shallow clone + * @throws InternalError if {@link AbstractMap#clone()} failed + */ + @Override + @SuppressWarnings("unchecked") + protected AbstractHashedMap clone() { + try { + final AbstractHashedMap cloned = (AbstractHashedMap) super.clone(); + cloned.data = new HashEntry[data.length]; + cloned.entrySet = null; + cloned.keySet = null; + cloned.values = null; + cloned.modCount = 0; + cloned.size = 0; + cloned.init(); + cloned.putAll(this); + return cloned; + } catch (final CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + /** + * Compares this map with another. + * + * @param obj the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map == false) { + return false; + } + final Map map = (Map) obj; + if (map.size() != size()) { + return false; + } + final MapIterator it = mapIterator(); + try { + while (it.hasNext()) { + final Object key = it.next(); + final Object value = it.getValue(); + if (value == null) { + if (map.get(key) != null || map.containsKey(key) == false) { + return false; + } + } else { + if (value.equals(map.get(key)) == false) { + return false; + } + } + } + } catch (final ClassCastException ignored) { + return false; + } catch (final NullPointerException ignored) { + return false; + } + return true; + } + + /** + * Gets the standard Map hashCode. + * + * @return the hash code defined in the Map interface + */ + @Override + public int hashCode() { + int total = 0; + final Iterator> it = createEntrySetIterator(); + while (it.hasNext()) { + total += it.next().hashCode(); + } + return total; + } + + /** + * Gets the map as a String. + * + * @return a string version of the map + */ + @Override + public String toString() { + if (size() == 0) { + return "{}"; + } + final StringBuilder buf = new StringBuilder(32 * size()); + buf.append('{'); + + final MapIterator it = mapIterator(); + boolean hasNext = it.hasNext(); + while (hasNext) { + final K key = it.next(); + final V value = it.getValue(); + buf.append(key == this ? "(this Map)" : key) + .append('=') + .append(value == this ? "(this Map)" : value); + + hasNext = it.hasNext(); + if (hasNext) { + buf.append(',').append(' '); + } + } + + buf.append('}'); + return buf.toString(); + } +} diff --git a/src/org/apache/commons/collections4/map/AbstractInputCheckedMapDecorator.java b/src/org/apache/commons/collections4/map/AbstractInputCheckedMapDecorator.java new file mode 100644 index 0000000..a862b5d --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractInputCheckedMapDecorator.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.lang.reflect.Array; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; +import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator; +import org.apache.commons.collections4.set.AbstractSetDecorator; + +/** + * An abstract base class that simplifies the task of creating map decorators. + *

              + * The Map API is very difficult to decorate correctly, and involves implementing + * lots of different classes. This class exists to provide a simpler API. + *

              + * Special hook methods are provided that are called when objects are added to + * the map. By overriding these methods, the input can be validated or manipulated. + * In addition to the main map methods, the entrySet is also affected, which is + * the hardest part of writing map implementations. + *

              + * This class is package-scoped, and may be withdrawn or replaced in future + * versions of Commons Collections. + * + * @since 3.1 + * @version $Id: AbstractInputCheckedMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +abstract class AbstractInputCheckedMapDecorator + extends AbstractMapDecorator { + + /** + * Constructor only used in deserialization, do not use otherwise. + */ + protected AbstractInputCheckedMapDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + protected AbstractInputCheckedMapDecorator(final Map map) { + super(map); + } + + //----------------------------------------------------------------------- + /** + * Hook method called when a value is being set using setValue. + *

              + * An implementation may validate the value and throw an exception + * or it may transform the value into another object. + *

              + * This implementation returns the input value. + * + * @param value the value to check + * @throws UnsupportedOperationException if the map may not be changed by setValue + * @throws IllegalArgumentException if the specified value is invalid + * @throws ClassCastException if the class of the specified value is invalid + * @throws NullPointerException if the specified value is null and nulls are invalid + */ + protected abstract V checkSetValue(V value); + + /** + * Hook method called to determine if checkSetValue has any effect. + *

              + * An implementation should return false if the checkSetValue method + * has no effect as this optimises the implementation. + *

              + * This implementation returns true. + * + * @return true always + */ + protected boolean isSetValueChecking() { + return true; + } + + //----------------------------------------------------------------------- + @Override + public Set> entrySet() { + if (isSetValueChecking()) { + return new EntrySet(map.entrySet(), this); + } + return map.entrySet(); + } + + //----------------------------------------------------------------------- + /** + * Implementation of an entry set that checks additions via setValue. + */ + private class EntrySet extends AbstractSetDecorator> { + + /** Generated serial version ID. */ + private static final long serialVersionUID = 4354731610923110264L; + + /** The parent map */ + private final AbstractInputCheckedMapDecorator parent; + + protected EntrySet(final Set> set, final AbstractInputCheckedMapDecorator parent) { + super(set); + this.parent = parent; + } + + @Override + public Iterator> iterator() { + return new EntrySetIterator(this.decorated().iterator(), parent); + } + + @Override + @SuppressWarnings("unchecked") + public Object[] toArray() { + final Object[] array = this.decorated().toArray(); + for (int i = 0; i < array.length; i++) { + array[i] = new MapEntry((Map.Entry) array[i], parent); + } + return array; + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(final T[] array) { + Object[] result = array; + if (array.length > 0) { + // we must create a new array to handle multi-threaded situations + // where another thread could access data before we decorate it + result = (Object[]) Array.newInstance(array.getClass().getComponentType(), 0); + } + result = this.decorated().toArray(result); + for (int i = 0; i < result.length; i++) { + result[i] = new MapEntry((Map.Entry) result[i], parent); + } + + // check to see if result should be returned straight + if (result.length > array.length) { + return (T[]) result; + } + + // copy back into input array to fulfil the method contract + System.arraycopy(result, 0, array, 0, result.length); + if (array.length > result.length) { + array[result.length] = null; + } + return array; + } + } + + /** + * Implementation of an entry set iterator that checks additions via setValue. + */ + private class EntrySetIterator extends AbstractIteratorDecorator> { + + /** The parent map */ + private final AbstractInputCheckedMapDecorator parent; + + protected EntrySetIterator(final Iterator> iterator, + final AbstractInputCheckedMapDecorator parent) { + super(iterator); + this.parent = parent; + } + + @Override + public Map.Entry next() { + final Map.Entry entry = getIterator().next(); + return new MapEntry(entry, parent); + } + } + + /** + * Implementation of a map entry that checks additions via setValue. + */ + private class MapEntry extends AbstractMapEntryDecorator { + + /** The parent map */ + private final AbstractInputCheckedMapDecorator parent; + + protected MapEntry(final Map.Entry entry, final AbstractInputCheckedMapDecorator parent) { + super(entry); + this.parent = parent; + } + + @Override + public V setValue(V value) { + value = parent.checkSetValue(value); + return getMapEntry().setValue(value); + } + } + +} diff --git a/src/org/apache/commons/collections4/map/AbstractIterableMap.java b/src/org/apache/commons/collections4/map/AbstractIterableMap.java new file mode 100644 index 0000000..27d712a --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractIterableMap.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import org.apache.commons.collections4.IterableMap; +import org.apache.commons.collections4.MapIterator; + +/** + * Provide a basic {@link IterableMap} implementation. + * + * @since 4.0 + * @version $Id: AbstractIterableMap.java 1469004 2013-04-17 17:37:03Z tn $ + */ +public abstract class AbstractIterableMap implements IterableMap { + + /** + * {@inheritDoc} + */ + public MapIterator mapIterator() { + return new EntrySetToMapIteratorAdapter(entrySet()); + } +} diff --git a/src/org/apache/commons/collections4/map/AbstractLinkedMap.java b/src/org/apache/commons/collections4/map/AbstractLinkedMap.java new file mode 100644 index 0000000..d7f5150 --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractLinkedMap.java @@ -0,0 +1,605 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; + +import org.apache.commons.collections4.OrderedIterator; +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.ResettableIterator; +import org.apache.commons.collections4.iterators.EmptyOrderedIterator; +import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator; + +/** + * An abstract implementation of a hash-based map that links entries to create an + * ordered map and which provides numerous points for subclasses to override. + *

              + * This class implements all the features necessary for a subclass linked + * hash-based map. Key-value entries are stored in instances of the + * LinkEntry class which can be overridden and replaced. + * The iterators can similarly be replaced, without the need to replace the KeySet, + * EntrySet and Values view classes. + *

              + * Overridable methods are provided to change the default hashing behaviour, and + * to change how entries are added to and removed from the map. Hopefully, all you + * need for unusual subclasses is here. + *

              + * This implementation maintains order by original insertion, but subclasses + * may work differently. The OrderedMap interface is implemented + * to provide access to bidirectional iteration and extra convenience methods. + *

              + * The orderedMapIterator() method provides direct access to a + * bidirectional iterator. The iterators from the other views can also be cast + * to OrderedIterator if required. + *

              + * All the available iterators can be reset back to the start by casting to + * ResettableIterator and calling reset(). + *

              + * The implementation is also designed to be subclassed, with lots of useful + * methods exposed. + * + * @since 3.0 + * @version $Id: AbstractLinkedMap.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public abstract class AbstractLinkedMap extends AbstractHashedMap implements OrderedMap { + + /** Header in the linked list */ + transient LinkEntry header; + + /** + * Constructor only used in deserialization, do not use otherwise. + */ + protected AbstractLinkedMap() { + super(); + } + + /** + * Constructor which performs no validation on the passed in parameters. + * + * @param initialCapacity the initial capacity, must be a power of two + * @param loadFactor the load factor, must be > 0.0f and generally < 1.0f + * @param threshold the threshold, must be sensible + */ + protected AbstractLinkedMap(final int initialCapacity, final float loadFactor, final int threshold) { + super(initialCapacity, loadFactor, threshold); + } + + /** + * Constructs a new, empty map with the specified initial capacity. + * + * @param initialCapacity the initial capacity + * @throws IllegalArgumentException if the initial capacity is negative + */ + protected AbstractLinkedMap(final int initialCapacity) { + super(initialCapacity); + } + + /** + * Constructs a new, empty map with the specified initial capacity and + * load factor. + * + * @param initialCapacity the initial capacity + * @param loadFactor the load factor + * @throws IllegalArgumentException if the initial capacity is negative + * @throws IllegalArgumentException if the load factor is less than zero + */ + protected AbstractLinkedMap(final int initialCapacity, final float loadFactor) { + super(initialCapacity, loadFactor); + } + + /** + * Constructor copying elements from another map. + * + * @param map the map to copy + * @throws NullPointerException if the map is null + */ + protected AbstractLinkedMap(final Map map) { + super(map); + } + + /** + * Initialise this subclass during construction. + *

              + * NOTE: As from v3.2 this method calls + * {@link #createEntry(HashEntry, int, Object, Object)} to create + * the map entry object. + */ + @Override + protected void init() { + header = createEntry(null, -1, null, null); + header.before = header.after = header; + } + + //----------------------------------------------------------------------- + /** + * Checks whether the map contains the specified value. + * + * @param value the value to search for + * @return true if the map contains the value + */ + @Override + public boolean containsValue(final Object value) { + // override uses faster iterator + if (value == null) { + for (LinkEntry entry = header.after; entry != header; entry = entry.after) { + if (entry.getValue() == null) { + return true; + } + } + } else { + for (LinkEntry entry = header.after; entry != header; entry = entry.after) { + if (isEqualValue(value, entry.getValue())) { + return true; + } + } + } + return false; + } + + /** + * Clears the map, resetting the size to zero and nullifying references + * to avoid garbage collection issues. + */ + @Override + public void clear() { + // override to reset the linked list + super.clear(); + header.before = header.after = header; + } + + //----------------------------------------------------------------------- + /** + * Gets the first key in the map, which is the first inserted. + * + * @return the eldest key + */ + public K firstKey() { + if (size == 0) { + throw new NoSuchElementException("Map is empty"); + } + return header.after.getKey(); + } + + /** + * Gets the last key in the map, which is the most recently inserted. + * + * @return the most recently inserted key + */ + public K lastKey() { + if (size == 0) { + throw new NoSuchElementException("Map is empty"); + } + return header.before.getKey(); + } + + /** + * Gets the next key in sequence. + * + * @param key the key to get after + * @return the next key + */ + public K nextKey(final Object key) { + final LinkEntry entry = getEntry(key); + return entry == null || entry.after == header ? null : entry.after.getKey(); + } + + @Override + protected LinkEntry getEntry(final Object key) { + return (LinkEntry) super.getEntry(key); + } + + /** + * Gets the previous key in sequence. + * + * @param key the key to get before + * @return the previous key + */ + public K previousKey(final Object key) { + final LinkEntry entry = getEntry(key); + return entry == null || entry.before == header ? null : entry.before.getKey(); + } + + //----------------------------------------------------------------------- + /** + * Gets the key at the specified index. + * + * @param index the index to retrieve + * @return the key at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + protected LinkEntry getEntry(final int index) { + if (index < 0) { + throw new IndexOutOfBoundsException("Index " + index + " is less than zero"); + } + if (index >= size) { + throw new IndexOutOfBoundsException("Index " + index + " is invalid for size " + size); + } + LinkEntry entry; + if (index < size / 2) { + // Search forwards + entry = header.after; + for (int currentIndex = 0; currentIndex < index; currentIndex++) { + entry = entry.after; + } + } else { + // Search backwards + entry = header; + for (int currentIndex = size; currentIndex > index; currentIndex--) { + entry = entry.before; + } + } + return entry; + } + + /** + * Adds an entry into this map, maintaining insertion order. + *

              + * This implementation adds the entry to the data storage table and + * to the end of the linked list. + * + * @param entry the entry to add + * @param hashIndex the index into the data array to store at + */ + @Override + protected void addEntry(final HashEntry entry, final int hashIndex) { + final LinkEntry link = (LinkEntry) entry; + link.after = header; + link.before = header.before; + header.before.after = link; + header.before = link; + data[hashIndex] = link; + } + + /** + * Creates an entry to store the data. + *

              + * This implementation creates a new LinkEntry instance. + * + * @param next the next entry in sequence + * @param hashCode the hash code to use + * @param key the key to store + * @param value the value to store + * @return the newly created entry + */ + @Override + protected LinkEntry createEntry(final HashEntry next, final int hashCode, final K key, final V value) { + return new LinkEntry(next, hashCode, convertKey(key), value); + } + + /** + * Removes an entry from the map and the linked list. + *

              + * This implementation removes the entry from the linked list chain, then + * calls the superclass implementation. + * + * @param entry the entry to remove + * @param hashIndex the index into the data structure + * @param previous the previous entry in the chain + */ + @Override + protected void removeEntry(final HashEntry entry, final int hashIndex, final HashEntry previous) { + final LinkEntry link = (LinkEntry) entry; + link.before.after = link.after; + link.after.before = link.before; + link.after = null; + link.before = null; + super.removeEntry(entry, hashIndex, previous); + } + + //----------------------------------------------------------------------- + /** + * Gets the before field from a LinkEntry. + * Used in subclasses that have no visibility of the field. + * + * @param entry the entry to query, must not be null + * @return the before field of the entry + * @throws NullPointerException if the entry is null + * @since 3.1 + */ + protected LinkEntry entryBefore(final LinkEntry entry) { + return entry.before; + } + + /** + * Gets the after field from a LinkEntry. + * Used in subclasses that have no visibility of the field. + * + * @param entry the entry to query, must not be null + * @return the after field of the entry + * @throws NullPointerException if the entry is null + * @since 3.1 + */ + protected LinkEntry entryAfter(final LinkEntry entry) { + return entry.after; + } + + //----------------------------------------------------------------------- + /** + * {@inheritDoc} + */ + @Override + public OrderedMapIterator mapIterator() { + if (size == 0) { + return EmptyOrderedMapIterator.emptyOrderedMapIterator(); + } + return new LinkMapIterator(this); + } + + /** + * MapIterator implementation. + */ + protected static class LinkMapIterator extends LinkIterator implements + OrderedMapIterator, ResettableIterator { + + protected LinkMapIterator(final AbstractLinkedMap parent) { + super(parent); + } + + public K next() { + return super.nextEntry().getKey(); + } + + public K previous() { + return super.previousEntry().getKey(); + } + + public K getKey() { + final LinkEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID); + } + return current.getKey(); + } + + public V getValue() { + final LinkEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID); + } + return current.getValue(); + } + + public V setValue(final V value) { + final LinkEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID); + } + return current.setValue(value); + } + } + + //----------------------------------------------------------------------- + /** + * Creates an entry set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the entrySet iterator + */ + @Override + protected Iterator> createEntrySetIterator() { + if (size() == 0) { + return EmptyOrderedIterator.>emptyOrderedIterator(); + } + return new EntrySetIterator(this); + } + + /** + * EntrySet iterator. + */ + protected static class EntrySetIterator extends LinkIterator implements + OrderedIterator>, ResettableIterator> { + + protected EntrySetIterator(final AbstractLinkedMap parent) { + super(parent); + } + + public Map.Entry next() { + return super.nextEntry(); + } + + public Map.Entry previous() { + return super.previousEntry(); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a key set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the keySet iterator + */ + @Override + protected Iterator createKeySetIterator() { + if (size() == 0) { + return EmptyOrderedIterator.emptyOrderedIterator(); + } + return new KeySetIterator(this); + } + + /** + * KeySet iterator. + */ + protected static class KeySetIterator extends LinkIterator implements + OrderedIterator, ResettableIterator { + + @SuppressWarnings("unchecked") + protected KeySetIterator(final AbstractLinkedMap parent) { + super((AbstractLinkedMap) parent); + } + + public K next() { + return super.nextEntry().getKey(); + } + + public K previous() { + return super.previousEntry().getKey(); + } + } + + //----------------------------------------------------------------------- + /** + * Creates a values iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the values iterator + */ + @Override + protected Iterator createValuesIterator() { + if (size() == 0) { + return EmptyOrderedIterator.emptyOrderedIterator(); + } + return new ValuesIterator(this); + } + + /** + * Values iterator. + */ + protected static class ValuesIterator extends LinkIterator implements + OrderedIterator, ResettableIterator { + + @SuppressWarnings("unchecked") + protected ValuesIterator(final AbstractLinkedMap parent) { + super((AbstractLinkedMap) parent); + } + + public V next() { + return super.nextEntry().getValue(); + } + + public V previous() { + return super.previousEntry().getValue(); + } + } + + //----------------------------------------------------------------------- + /** + * LinkEntry that stores the data. + *

              + * If you subclass AbstractLinkedMap but not LinkEntry + * then you will not be able to access the protected fields. + * The entryXxx() methods on AbstractLinkedMap exist + * to provide the necessary access. + */ + protected static class LinkEntry extends HashEntry { + /** The entry before this one in the order */ + protected LinkEntry before; + /** The entry after this one in the order */ + protected LinkEntry after; + + /** + * Constructs a new entry. + * + * @param next the next entry in the hash bucket sequence + * @param hashCode the hash code + * @param key the key + * @param value the value + */ + protected LinkEntry(final HashEntry next, final int hashCode, final Object key, final V value) { + super(next, hashCode, key, value); + } + } + + /** + * Base Iterator that iterates in link order. + */ + protected static abstract class LinkIterator { + + /** The parent map */ + protected final AbstractLinkedMap parent; + /** The current (last returned) entry */ + protected LinkEntry last; + /** The next entry */ + protected LinkEntry next; + /** The modification count expected */ + protected int expectedModCount; + + protected LinkIterator(final AbstractLinkedMap parent) { + super(); + this.parent = parent; + this.next = parent.header.after; + this.expectedModCount = parent.modCount; + } + + public boolean hasNext() { + return next != parent.header; + } + + public boolean hasPrevious() { + return next.before != parent.header; + } + + protected LinkEntry nextEntry() { + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + if (next == parent.header) { + throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY); + } + last = next; + next = next.after; + return last; + } + + protected LinkEntry previousEntry() { + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + final LinkEntry previous = next.before; + if (previous == parent.header) { + throw new NoSuchElementException(AbstractHashedMap.NO_PREVIOUS_ENTRY); + } + next = previous; + last = previous; + return last; + } + + protected LinkEntry currentEntry() { + return last; + } + + public void remove() { + if (last == null) { + throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID); + } + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + parent.remove(last.getKey()); + last = null; + expectedModCount = parent.modCount; + } + + public void reset() { + last = null; + next = parent.header.after; + } + + @Override + public String toString() { + if (last != null) { + return "Iterator[" + last.getKey() + "=" + last.getValue() + "]"; + } + return "Iterator[]"; + } + } + +} diff --git a/src/org/apache/commons/collections4/map/AbstractMapDecorator.java b/src/org/apache/commons/collections4/map/AbstractMapDecorator.java new file mode 100644 index 0000000..6c48bdc --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractMapDecorator.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * Provides a base decorator that enables additional functionality to be added + * to a Map via decoration. + *

              + * Methods are forwarded directly to the decorated map. + *

              + * This implementation does not perform any special processing with + * {@link #entrySet()}, {@link #keySet()} or {@link #values()}. Instead + * it simply returns the set/collection from the wrapped map. This may be + * undesirable, for example if you are trying to write a validating + * implementation it would provide a loophole around the validation. + * But, you might want that loophole, so this class is kept simple. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * @since 3.0 + * @version $Id: AbstractMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractMapDecorator extends AbstractIterableMap { + + /** The map to decorate */ + transient Map map; + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractMapDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if the map is null + */ + protected AbstractMapDecorator(final Map map) { + if (map == null) { + throw new NullPointerException("Map must not be null."); + } + this.map = map; + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + protected Map decorated() { + return map; + } + + //----------------------------------------------------------------------- + public void clear() { + decorated().clear(); + } + + public boolean containsKey(final Object key) { + return decorated().containsKey(key); + } + + public boolean containsValue(final Object value) { + return decorated().containsValue(value); + } + + public Set> entrySet() { + return decorated().entrySet(); + } + + public V get(final Object key) { + return decorated().get(key); + } + + public boolean isEmpty() { + return decorated().isEmpty(); + } + + public Set keySet() { + return decorated().keySet(); + } + + public V put(final K key, final V value) { + return decorated().put(key, value); + } + + public void putAll(final Map mapToCopy) { + decorated().putAll(mapToCopy); + } + + public V remove(final Object key) { + return decorated().remove(key); + } + + public int size() { + return decorated().size(); + } + + public Collection values() { + return decorated().values(); + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + return decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + @Override + public String toString() { + return decorated().toString(); + } + +} diff --git a/src/org/apache/commons/collections4/map/AbstractOrderedMapDecorator.java b/src/org/apache/commons/collections4/map/AbstractOrderedMapDecorator.java new file mode 100644 index 0000000..7a0eaaf --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractOrderedMapDecorator.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.OrderedMapIterator; + +/** + * Provides a base decorator that enables additional functionality to be added + * to an OrderedMap via decoration. + *

              + * Methods are forwarded directly to the decorated map. + *

              + * This implementation does not perform any special processing with the map views. + * Instead it simply returns the set/collection from the wrapped map. This may be + * undesirable, for example if you are trying to write a validating implementation + * it would provide a loophole around the validation. + * But, you might want that loophole, so this class is kept simple. + * + * @since 3.0 + * @version $Id: AbstractOrderedMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractOrderedMapDecorator extends AbstractMapDecorator + implements OrderedMap { + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractOrderedMapDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if the map is null + */ + public AbstractOrderedMapDecorator(final OrderedMap map) { + super(map); + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + @Override + protected OrderedMap decorated() { + return (OrderedMap) super.decorated(); + } + + //----------------------------------------------------------------------- + public K firstKey() { + return decorated().firstKey(); + } + + public K lastKey() { + return decorated().lastKey(); + } + + public K nextKey(final K key) { + return decorated().nextKey(key); + } + + public K previousKey(final K key) { + return decorated().previousKey(key); + } + + @Override + public OrderedMapIterator mapIterator() { + return decorated().mapIterator(); + } + +} diff --git a/src/org/apache/commons/collections4/map/AbstractReferenceMap.java b/src/org/apache/commons/collections4/map/AbstractReferenceMap.java new file mode 100644 index 0000000..1b091f6 --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractReferenceMap.java @@ -0,0 +1,1058 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.keyvalue.DefaultMapEntry; + +/** + * An abstract implementation of a hash-based map that allows the entries to + * be removed by the garbage collector. + *

              + * This class implements all the features necessary for a subclass reference + * hash-based map. Key-value entries are stored in instances of the + * ReferenceEntry class which can be overridden and replaced. + * The iterators can similarly be replaced, without the need to replace the KeySet, + * EntrySet and Values view classes. + *

              + * Overridable methods are provided to change the default hashing behaviour, and + * to change how entries are added to and removed from the map. Hopefully, all you + * need for unusual subclasses is here. + *

              + * When you construct an AbstractReferenceMap, you can specify what + * kind of references are used to store the map's keys and values. + * If non-hard references are used, then the garbage collector can remove + * mappings if a key or value becomes unreachable, or if the JVM's memory is + * running low. For information on how the different reference types behave, + * see {@link Reference}. + *

              + * Different types of references can be specified for keys and values. + * The keys can be configured to be weak but the values hard, + * in which case this class will behave like a + * + * WeakHashMap. However, you can also specify hard keys and + * weak values, or any other combination. The default constructor uses + * hard keys and soft values, providing a memory-sensitive cache. + *

              + * This {@link Map} implementation does not allow null elements. + * Attempting to add a null key or value to the map will raise a + * NullPointerException. + *

              + * All the available iterators can be reset back to the start by casting to + * ResettableIterator and calling reset(). + *

              + * This implementation is not synchronized. + * You can use {@link java.util.Collections#synchronizedMap} to + * provide synchronized access to a ReferenceMap. + * + * @see java.lang.ref.Reference + * @since 3.1 (extracted from ReferenceMap in 3.0) + * @version $Id: AbstractReferenceMap.java 1477799 2013-04-30 19:56:11Z tn $ + */ +public abstract class AbstractReferenceMap extends AbstractHashedMap { + + /** + * Reference type enum. + */ + public static enum ReferenceStrength { + HARD(0), SOFT(1), WEAK(2); + + /** value */ + public final int value; + + /** + * Resolve enum from int. + * @param value the int value + * @return ReferenceType + * @throws IllegalArgumentException if the specified value is invalid. + */ + public static ReferenceStrength resolve(final int value) { + switch (value) { + case 0: + return HARD; + case 1: + return SOFT; + case 2: + return WEAK; + default: + throw new IllegalArgumentException(); + } + } + + private ReferenceStrength(final int value) { + this.value = value; + } + + } + + /** + * The reference type for keys. + */ + private ReferenceStrength keyType; + + /** + * The reference type for values. + */ + private ReferenceStrength valueType; + + /** + * Should the value be automatically purged when the associated key has been collected? + */ + private boolean purgeValues; + + /** + * ReferenceQueue used to eliminate stale mappings. + * See purge. + */ + private transient ReferenceQueue queue; + + //----------------------------------------------------------------------- + /** + * Constructor used during deserialization. + */ + protected AbstractReferenceMap() { + super(); + } + + /** + * Constructs a new empty map with the specified reference types, + * load factor and initial capacity. + * + * @param keyType the type of reference to use for keys; + * must be {@link ReferenceStrength#HARD HARD}, + * {@link ReferenceStrength#SOFT SOFT}, + * {@link ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link ReferenceStrength#HARD}, + * {@link ReferenceStrength#SOFT SOFT}, + * {@link ReferenceStrength#WEAK WEAK} + * @param capacity the initial capacity for the map + * @param loadFactor the load factor for the map + * @param purgeValues should the value be automatically purged when the + * key is garbage collected + */ + protected AbstractReferenceMap( + final ReferenceStrength keyType, final ReferenceStrength valueType, final int capacity, + final float loadFactor, final boolean purgeValues) { + super(capacity, loadFactor); + this.keyType = keyType; + this.valueType = valueType; + this.purgeValues = purgeValues; + } + + /** + * Initialise this subclass during construction, cloning or deserialization. + */ + @Override + protected void init() { + queue = new ReferenceQueue(); + } + + //----------------------------------------------------------------------- + /** + * Gets the size of the map. + * + * @return the size + */ + @Override + public int size() { + purgeBeforeRead(); + return super.size(); + } + + /** + * Checks whether the map is currently empty. + * + * @return true if the map is currently size zero + */ + @Override + public boolean isEmpty() { + purgeBeforeRead(); + return super.isEmpty(); + } + + /** + * Checks whether the map contains the specified key. + * + * @param key the key to search for + * @return true if the map contains the key + */ + @Override + public boolean containsKey(final Object key) { + purgeBeforeRead(); + final Entry entry = getEntry(key); + if (entry == null) { + return false; + } + return entry.getValue() != null; + } + + /** + * Checks whether the map contains the specified value. + * + * @param value the value to search for + * @return true if the map contains the value + */ + @Override + public boolean containsValue(final Object value) { + purgeBeforeRead(); + if (value == null) { + return false; + } + return super.containsValue(value); + } + + /** + * Gets the value mapped to the key specified. + * + * @param key the key + * @return the mapped value, null if no match + */ + @Override + public V get(final Object key) { + purgeBeforeRead(); + final Entry entry = getEntry(key); + if (entry == null) { + return null; + } + return entry.getValue(); + } + + + /** + * Puts a key-value mapping into this map. + * Neither the key nor the value may be null. + * + * @param key the key to add, must not be null + * @param value the value to add, must not be null + * @return the value previously mapped to this key, null if none + * @throws NullPointerException if either the key or value is null + */ + @Override + public V put(final K key, final V value) { + if (key == null) { + throw new NullPointerException("null keys not allowed"); + } + if (value == null) { + throw new NullPointerException("null values not allowed"); + } + + purgeBeforeWrite(); + return super.put(key, value); + } + + /** + * Removes the specified mapping from this map. + * + * @param key the mapping to remove + * @return the value mapped to the removed key, null if key not in map + */ + @Override + public V remove(final Object key) { + if (key == null) { + return null; + } + purgeBeforeWrite(); + return super.remove(key); + } + + /** + * Clears this map. + */ + @Override + public void clear() { + super.clear(); + while (queue.poll() != null) {} // drain the queue + } + + //----------------------------------------------------------------------- + /** + * Gets a MapIterator over the reference map. + * The iterator only returns valid key/value pairs. + * + * @return a map iterator + */ + @Override + public MapIterator mapIterator() { + return new ReferenceMapIterator(this); + } + + /** + * Returns a set view of this map's entries. + * An iterator returned entry is valid until next() is called again. + * The setValue() method on the toArray entries has no effect. + * + * @return a set view of this map's entries + */ + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = new ReferenceEntrySet(this); + } + return entrySet; + } + + /** + * Returns a set view of this map's keys. + * + * @return a set view of this map's keys + */ + @Override + public Set keySet() { + if (keySet == null) { + keySet = new ReferenceKeySet(this); + } + return keySet; + } + + /** + * Returns a collection view of this map's values. + * + * @return a set view of this map's values + */ + @Override + public Collection values() { + if (values == null) { + values = new ReferenceValues(this); + } + return values; + } + + //----------------------------------------------------------------------- + /** + * Purges stale mappings from this map before read operations. + *

              + * This implementation calls {@link #purge()} to maintain a consistent state. + */ + protected void purgeBeforeRead() { + purge(); + } + + /** + * Purges stale mappings from this map before write operations. + *

              + * This implementation calls {@link #purge()} to maintain a consistent state. + */ + protected void purgeBeforeWrite() { + purge(); + } + + /** + * Purges stale mappings from this map. + *

              + * Note that this method is not synchronized! Special + * care must be taken if, for instance, you want stale + * mappings to be removed on a periodic basis by some + * background thread. + */ + protected void purge() { + Reference ref = queue.poll(); + while (ref != null) { + purge(ref); + ref = queue.poll(); + } + } + + /** + * Purges the specified reference. + * + * @param ref the reference to purge + */ + protected void purge(final Reference ref) { + // The hashCode of the reference is the hashCode of the + // mapping key, even if the reference refers to the + // mapping value... + final int hash = ref.hashCode(); + final int index = hashIndex(hash, data.length); + HashEntry previous = null; + HashEntry entry = data[index]; + while (entry != null) { + if (((ReferenceEntry) entry).purge(ref)) { + if (previous == null) { + data[index] = entry.next; + } else { + previous.next = entry.next; + } + this.size--; + return; + } + previous = entry; + entry = entry.next; + } + + } + + //----------------------------------------------------------------------- + /** + * Gets the entry mapped to the key specified. + * + * @param key the key + * @return the entry, null if no match + */ + @Override + protected HashEntry getEntry(final Object key) { + if (key == null) { + return null; + } + return super.getEntry(key); + } + + /** + * Gets the hash code for a MapEntry. + * Subclasses can override this, for example to use the identityHashCode. + * + * @param key the key to get a hash code for, may be null + * @param value the value to get a hash code for, may be null + * @return the hash code, as per the MapEntry specification + */ + protected int hashEntry(final Object key, final Object value) { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + /** + * Compares two keys, in internal converted form, to see if they are equal. + *

              + * This implementation converts the key from the entry to a real reference + * before comparison. + * + * @param key1 the first key to compare passed in from outside + * @param key2 the second key extracted from the entry via entry.key + * @return true if equal + */ + @Override + @SuppressWarnings("unchecked") + protected boolean isEqualKey(final Object key1, Object key2) { + key2 = keyType == ReferenceStrength.HARD ? key2 : ((Reference) key2).get(); + return key1 == key2 || key1.equals(key2); + } + + /** + * Creates a ReferenceEntry instead of a HashEntry. + * + * @param next the next entry in sequence + * @param hashCode the hash code to use + * @param key the key to store + * @param value the value to store + * @return the newly created entry + */ + @Override + protected ReferenceEntry createEntry(final HashEntry next, final int hashCode, + final K key, final V value) { + return new ReferenceEntry(this, next, hashCode, key, value); + } + + /** + * Creates an entry set iterator. + * + * @return the entrySet iterator + */ + @Override + protected Iterator> createEntrySetIterator() { + return new ReferenceEntrySetIterator(this); + } + + /** + * Creates an key set iterator. + * + * @return the keySet iterator + */ + @Override + protected Iterator createKeySetIterator() { + return new ReferenceKeySetIterator(this); + } + + /** + * Creates an values iterator. + * + * @return the values iterator + */ + @Override + protected Iterator createValuesIterator() { + return new ReferenceValuesIterator(this); + } + + //----------------------------------------------------------------------- + /** + * EntrySet implementation. + */ + static class ReferenceEntrySet extends EntrySet { + + protected ReferenceEntrySet(final AbstractHashedMap parent) { + super(parent); + } + + @Override + public Object[] toArray() { + return toArray(new Object[size()]); + } + + @Override + public T[] toArray(final T[] arr) { + // special implementation to handle disappearing entries + final ArrayList> list = new ArrayList>(size()); + for (final Map.Entry entry : this) { + list.add(new DefaultMapEntry(entry)); + } + return list.toArray(arr); + } + } + + //----------------------------------------------------------------------- + /** + * KeySet implementation. + */ + static class ReferenceKeySet extends KeySet { + + protected ReferenceKeySet(final AbstractHashedMap parent) { + super(parent); + } + + @Override + public Object[] toArray() { + return toArray(new Object[size()]); + } + + @Override + public T[] toArray(final T[] arr) { + // special implementation to handle disappearing keys + final List list = new ArrayList(size()); + for (final K key : this) { + list.add(key); + } + return list.toArray(arr); + } + } + + //----------------------------------------------------------------------- + /** + * Values implementation. + */ + static class ReferenceValues extends Values { + + protected ReferenceValues(final AbstractHashedMap parent) { + super(parent); + } + + @Override + public Object[] toArray() { + return toArray(new Object[size()]); + } + + @Override + public T[] toArray(final T[] arr) { + // special implementation to handle disappearing values + final List list = new ArrayList(size()); + for (final V value : this) { + list.add(value); + } + return list.toArray(arr); + } + } + + //----------------------------------------------------------------------- + /** + * A MapEntry implementation for the map. + *

              + * If getKey() or getValue() returns null, it means + * the mapping is stale and should be removed. + * + * @since 3.1 + */ + protected static class ReferenceEntry extends HashEntry { + /** The parent map */ + private final AbstractReferenceMap parent; + + /** + * Creates a new entry object for the ReferenceMap. + * + * @param parent the parent map + * @param next the next entry in the hash bucket + * @param hashCode the hash code of the key + * @param key the key + * @param value the value + */ + public ReferenceEntry(final AbstractReferenceMap parent, final HashEntry next, + final int hashCode, final K key, final V value) { + super(next, hashCode, null, null); + this.parent = parent; + this.key = toReference(parent.keyType, key, hashCode); + this.value = toReference(parent.valueType, value, hashCode); // the key hashCode is passed in deliberately + } + + /** + * Gets the key from the entry. + * This method dereferences weak and soft keys and thus may return null. + * + * @return the key, which may be null if it was garbage collected + */ + @Override + @SuppressWarnings("unchecked") + public K getKey() { + return (K) (parent.keyType == ReferenceStrength.HARD ? key : ((Reference) key).get()); + } + + /** + * Gets the value from the entry. + * This method dereferences weak and soft value and thus may return null. + * + * @return the value, which may be null if it was garbage collected + */ + @Override + @SuppressWarnings("unchecked") + public V getValue() { + return (V) (parent.valueType == ReferenceStrength.HARD ? value : ((Reference) value).get()); + } + + /** + * Sets the value of the entry. + * + * @param obj the object to store + * @return the previous value + */ + @Override + @SuppressWarnings("unchecked") + public V setValue(final V obj) { + final V old = getValue(); + if (parent.valueType != ReferenceStrength.HARD) { + ((Reference) value).clear(); + } + value = toReference(parent.valueType, obj, hashCode); + return old; + } + + /** + * Compares this map entry to another. + *

              + * This implementation uses isEqualKey and + * isEqualValue on the main map for comparison. + * + * @param obj the other map entry to compare to + * @return true if equal, false if not + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map.Entry == false) { + return false; + } + + final Map.Entry entry = (Map.Entry)obj; + final Object entryKey = entry.getKey(); // convert to hard reference + final Object entryValue = entry.getValue(); // convert to hard reference + if (entryKey == null || entryValue == null) { + return false; + } + // compare using map methods, aiding identity subclass + // note that key is direct access and value is via method + return parent.isEqualKey(entryKey, key) && + parent.isEqualValue(entryValue, getValue()); + } + + /** + * Gets the hashcode of the entry using temporary hard references. + *

              + * This implementation uses hashEntry on the main map. + * + * @return the hashcode of the entry + */ + @Override + public int hashCode() { + return parent.hashEntry(getKey(), getValue()); + } + + /** + * Constructs a reference of the given type to the given referent. + * The reference is registered with the queue for later purging. + * + * @param the type of the referenced object + * @param type HARD, SOFT or WEAK + * @param referent the object to refer to + * @param hash the hash code of the key of the mapping; + * this number might be different from referent.hashCode() if + * the referent represents a value and not a key + * @return the reference to the object + */ + protected Object toReference(final ReferenceStrength type, final T referent, final int hash) { + if (type == ReferenceStrength.HARD) { + return referent; + } + if (type == ReferenceStrength.SOFT) { + return new SoftRef(hash, referent, parent.queue); + } + if (type == ReferenceStrength.WEAK) { + return new WeakRef(hash, referent, parent.queue); + } + throw new Error(); + } + + /** + * Purges the specified reference + * @param ref the reference to purge + * @return true or false + */ + boolean purge(final Reference ref) { + boolean r = parent.keyType != ReferenceStrength.HARD && key == ref; + r = r || parent.valueType != ReferenceStrength.HARD && value == ref; + if (r) { + if (parent.keyType != ReferenceStrength.HARD) { + ((Reference) key).clear(); + } + if (parent.valueType != ReferenceStrength.HARD) { + ((Reference) value).clear(); + } else if (parent.purgeValues) { + value = null; + } + } + return r; + } + + /** + * Gets the next entry in the bucket. + * + * @return the next entry in the bucket + */ + protected ReferenceEntry next() { + return (ReferenceEntry) next; + } + } + + //----------------------------------------------------------------------- + /** + * Base iterator class. + */ + static class ReferenceBaseIterator { + /** The parent map */ + final AbstractReferenceMap parent; + + // These fields keep track of where we are in the table. + int index; + ReferenceEntry entry; + ReferenceEntry previous; + + // These Object fields provide hard references to the + // current and next entry; this assures that if hasNext() + // returns true, next() will actually return a valid element. + K currentKey, nextKey; + V currentValue, nextValue; + + int expectedModCount; + + public ReferenceBaseIterator(final AbstractReferenceMap parent) { + super(); + this.parent = parent; + index = parent.size() != 0 ? parent.data.length : 0; + // have to do this here! size() invocation above + // may have altered the modCount. + expectedModCount = parent.modCount; + } + + public boolean hasNext() { + checkMod(); + while (nextNull()) { + ReferenceEntry e = entry; + int i = index; + while (e == null && i > 0) { + i--; + e = (ReferenceEntry) parent.data[i]; + } + entry = e; + index = i; + if (e == null) { + currentKey = null; + currentValue = null; + return false; + } + nextKey = e.getKey(); + nextValue = e.getValue(); + if (nextNull()) { + entry = entry.next(); + } + } + return true; + } + + private void checkMod() { + if (parent.modCount != expectedModCount) { + throw new ConcurrentModificationException(); + } + } + + private boolean nextNull() { + return nextKey == null || nextValue == null; + } + + protected ReferenceEntry nextEntry() { + checkMod(); + if (nextNull() && !hasNext()) { + throw new NoSuchElementException(); + } + previous = entry; + entry = entry.next(); + currentKey = nextKey; + currentValue = nextValue; + nextKey = null; + nextValue = null; + return previous; + } + + protected ReferenceEntry currentEntry() { + checkMod(); + return previous; + } + + public void remove() { + checkMod(); + if (previous == null) { + throw new IllegalStateException(); + } + parent.remove(currentKey); + previous = null; + currentKey = null; + currentValue = null; + expectedModCount = parent.modCount; + } + } + + /** + * The EntrySet iterator. + */ + static class ReferenceEntrySetIterator + extends ReferenceBaseIterator implements Iterator> { + + public ReferenceEntrySetIterator(final AbstractReferenceMap parent) { + super(parent); + } + + public Map.Entry next() { + return nextEntry(); + } + + } + + /** + * The keySet iterator. + */ + static class ReferenceKeySetIterator extends ReferenceBaseIterator implements Iterator { + + @SuppressWarnings("unchecked") + ReferenceKeySetIterator(final AbstractReferenceMap parent) { + super((AbstractReferenceMap) parent); + } + + public K next() { + return nextEntry().getKey(); + } + } + + /** + * The values iterator. + */ + static class ReferenceValuesIterator extends ReferenceBaseIterator implements Iterator { + + @SuppressWarnings("unchecked") + ReferenceValuesIterator(final AbstractReferenceMap parent) { + super((AbstractReferenceMap) parent); + } + + public V next() { + return nextEntry().getValue(); + } + } + + /** + * The MapIterator implementation. + */ + static class ReferenceMapIterator extends ReferenceBaseIterator implements MapIterator { + + protected ReferenceMapIterator(final AbstractReferenceMap parent) { + super(parent); + } + + public K next() { + return nextEntry().getKey(); + } + + public K getKey() { + final HashEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID); + } + return current.getKey(); + } + + public V getValue() { + final HashEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID); + } + return current.getValue(); + } + + public V setValue(final V value) { + final HashEntry current = currentEntry(); + if (current == null) { + throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID); + } + return current.setValue(value); + } + } + + //----------------------------------------------------------------------- + // These two classes store the hashCode of the key of + // of the mapping, so that after they're dequeued a quick + // lookup of the bucket in the table can occur. + + /** + * A soft reference holder. + */ + static class SoftRef extends SoftReference { + /** the hashCode of the key (even if the reference points to a value) */ + private final int hash; + + public SoftRef(final int hash, final T r, final ReferenceQueue q) { + super(r, q); + this.hash = hash; + } + + @Override + public int hashCode() { + return hash; + } + } + + /** + * A weak reference holder. + */ + static class WeakRef extends WeakReference { + /** the hashCode of the key (even if the reference points to a value) */ + private final int hash; + + public WeakRef(final int hash, final T r, final ReferenceQueue q) { + super(r, q); + this.hash = hash; + } + + @Override + public int hashCode() { + return hash; + } + } + + //----------------------------------------------------------------------- + /** + * Replaces the superclass method to store the state of this class. + *

              + * Serialization is not one of the JDK's nicest topics. Normal serialization will + * initialise the superclass before the subclass. Sometimes however, this isn't + * what you want, as in this case the put() method on read can be + * affected by subclass state. + *

              + * The solution adopted here is to serialize the state data of this class in + * this protected method. This method must be called by the + * writeObject() of the first serializable subclass. + *

              + * Subclasses may override if they have a specific field that must be present + * on read before this implementation will work. Generally, the read determines + * what must be serialized here, if anything. + * + * @param out the output stream + * @throws IOException if an error occurs while writing to the stream + */ + @Override + protected void doWriteObject(final ObjectOutputStream out) throws IOException { + out.writeInt(keyType.value); + out.writeInt(valueType.value); + out.writeBoolean(purgeValues); + out.writeFloat(loadFactor); + out.writeInt(data.length); + for (final MapIterator it = mapIterator(); it.hasNext();) { + out.writeObject(it.next()); + out.writeObject(it.getValue()); + } + out.writeObject(null); // null terminate map + // do not call super.doWriteObject() as code there doesn't work for reference map + } + + /** + * Replaces the superclass method to read the state of this class. + *

              + * Serialization is not one of the JDK's nicest topics. Normal serialization will + * initialise the superclass before the subclass. Sometimes however, this isn't + * what you want, as in this case the put() method on read can be + * affected by subclass state. + *

              + * The solution adopted here is to deserialize the state data of this class in + * this protected method. This method must be called by the + * readObject() of the first serializable subclass. + *

              + * Subclasses may override if the subclass has a specific field that must be present + * before put() or calculateThreshold() will work correctly. + * + * @param in the input stream + * @throws IOException if an error occurs while reading from the stream + * @throws ClassNotFoundException if an object read from the stream can not be loaded + */ + @Override + @SuppressWarnings("unchecked") + protected void doReadObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + this.keyType = ReferenceStrength.resolve(in.readInt()); + this.valueType = ReferenceStrength.resolve(in.readInt()); + this.purgeValues = in.readBoolean(); + this.loadFactor = in.readFloat(); + final int capacity = in.readInt(); + init(); + data = new HashEntry[capacity]; + while (true) { + final K key = (K) in.readObject(); + if (key == null) { + break; + } + final V value = (V) in.readObject(); + put(key, value); + } + threshold = calculateThreshold(data.length, loadFactor); + // do not call super.doReadObject() as code there doesn't work for reference map + } + + /** + * Provided protected read-only access to the key type. + * @param type the type to check against. + * @return true if keyType has the specified type + */ + protected boolean isKeyType(ReferenceStrength type) { + return this.keyType == type; + } +} diff --git a/src/org/apache/commons/collections4/map/AbstractSortedMapDecorator.java b/src/org/apache/commons/collections4/map/AbstractSortedMapDecorator.java new file mode 100644 index 0000000..1a63559 --- /dev/null +++ b/src/org/apache/commons/collections4/map/AbstractSortedMapDecorator.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.Comparator; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.apache.commons.collections4.IterableSortedMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.iterators.ListIteratorWrapper; + +/** + * Provides a base decorator that enables additional functionality to be added + * to a Map via decoration. + *

              + * Methods are forwarded directly to the decorated map. + *

              + * This implementation does not perform any special processing with the map views. + * Instead it simply returns the set/collection from the wrapped map. This may be + * undesirable, for example if you are trying to write a validating implementation + * it would provide a loophole around the validation. + * But, you might want that loophole, so this class is kept simple. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * @since 3.0 + * @version $Id: AbstractSortedMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractSortedMapDecorator extends AbstractMapDecorator implements + IterableSortedMap { + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractSortedMapDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if the map is null + */ + public AbstractSortedMapDecorator(final SortedMap map) { + super(map); + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + @Override + protected SortedMap decorated() { + return (SortedMap) super.decorated(); + } + + //----------------------------------------------------------------------- + public Comparator comparator() { + return decorated().comparator(); + } + + public K firstKey() { + return decorated().firstKey(); + } + + public K lastKey() { + return decorated().lastKey(); + } + + public SortedMap subMap(final K fromKey, final K toKey) { + return decorated().subMap(fromKey, toKey); + } + + public SortedMap headMap(final K toKey) { + return decorated().headMap(toKey); + } + + public SortedMap tailMap(final K fromKey) { + return decorated().tailMap(fromKey); + } + + public K previousKey(final K key) { + final SortedMap headMap = headMap(key); + return headMap.isEmpty() ? null : headMap.lastKey(); + } + + public K nextKey(final K key) { + final Iterator it = tailMap(key).keySet().iterator(); + it.next(); + return it.hasNext() ? it.next() : null; + } + + /** + * {@inheritDoc} + */ + @Override + public OrderedMapIterator mapIterator() { + return new SortedMapIterator(entrySet()); + } + + /** + * OrderedMapIterator implementation. + * + * @param the key type + * @param the value type + */ + protected static class SortedMapIterator extends EntrySetToMapIteratorAdapter + implements OrderedMapIterator { + + /** + * Create a new AbstractSortedMapDecorator.SortedMapIterator. + * @param entrySet the entrySet to iterate + */ + protected SortedMapIterator(final Set> entrySet) { + super(entrySet); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void reset() { + super.reset(); + iterator = new ListIteratorWrapper>(iterator); + } + + /** + * {@inheritDoc} + */ + public boolean hasPrevious() { + return ((ListIterator>) iterator).hasPrevious(); + } + + /** + * {@inheritDoc} + */ + public K previous() { + entry = ((ListIterator>) iterator).previous(); + return getKey(); + } + } +} diff --git a/src/org/apache/commons/collections4/map/CaseInsensitiveMap.java b/src/org/apache/commons/collections4/map/CaseInsensitiveMap.java new file mode 100644 index 0000000..5489c08 --- /dev/null +++ b/src/org/apache/commons/collections4/map/CaseInsensitiveMap.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +/** + * A case-insensitive Map. + *

              + * Before keys are added to the map or compared to other existing keys, they are converted + * to all lowercase in a locale-independent fashion by using information from the Unicode + * data file. + *

              + * Null keys are supported. + *

              + * The keySet() method returns all lowercase keys, or nulls. + *

              + * Example: + *

              
              + *  Map<String, String> map = new CaseInsensitiveMap<String, String>();
              + *  map.put("One", "One");
              + *  map.put("Two", "Two");
              + *  map.put(null, "Three");
              + *  map.put("one", "Four");
              + * 
              + * creates a CaseInsensitiveMap with three entries.
              + * map.get(null) returns "Three" and map.get("ONE") + * returns "Four". The Set returned by keySet() + * equals {"one", "two", null}. + *

              + * This map will violate the detail of various Map and map view contracts. + * As a general rule, don't compare this map to other maps. In particular, you can't + * use decorators like {@link ListOrderedMap} on it, which silently assume that these + * contracts are fulfilled. + *

              + * Note that CaseInsensitiveMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 3.0 + * @version $Id: CaseInsensitiveMap.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public class CaseInsensitiveMap extends AbstractHashedMap implements Serializable, Cloneable { + + /** Serialisation version */ + private static final long serialVersionUID = -7074655917369299456L; + + /** + * Constructs a new empty map with default size and load factor. + */ + public CaseInsensitiveMap() { + super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD); + } + + /** + * Constructs a new, empty map with the specified initial capacity. + * + * @param initialCapacity the initial capacity + * @throws IllegalArgumentException if the initial capacity is negative + */ + public CaseInsensitiveMap(final int initialCapacity) { + super(initialCapacity); + } + + /** + * Constructs a new, empty map with the specified initial capacity and + * load factor. + * + * @param initialCapacity the initial capacity + * @param loadFactor the load factor + * @throws IllegalArgumentException if the initial capacity is negative + * @throws IllegalArgumentException if the load factor is less than zero + */ + public CaseInsensitiveMap(final int initialCapacity, final float loadFactor) { + super(initialCapacity, loadFactor); + } + + /** + * Constructor copying elements from another map. + *

              + * Keys will be converted to lower case strings, which may cause + * some entries to be removed (if string representation of keys differ + * only by character case). + * + * @param map the map to copy + * @throws NullPointerException if the map is null + */ + public CaseInsensitiveMap(final Map map) { + super(map); + } + + //----------------------------------------------------------------------- + /** + * Overrides convertKey() from {@link AbstractHashedMap} to convert keys to + * lower case. + *

              + * Returns {@link AbstractHashedMap#NULL} if key is null. + * + * @param key the key convert + * @return the converted key + */ + @Override + protected Object convertKey(final Object key) { + if (key != null) { + final char[] chars = key.toString().toCharArray(); + for (int i = chars.length - 1; i >= 0; i--) { + chars[i] = Character.toLowerCase(Character.toUpperCase(chars[i])); + } + return new String(chars); + } + return AbstractHashedMap.NULL; + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the keys or values. + * + * @return a shallow clone + */ + @Override + public CaseInsensitiveMap clone() { + return (CaseInsensitiveMap) super.clone(); + } + + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Read the map in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + +} diff --git a/src/org/apache/commons/collections4/map/CompositeMap.java b/src/org/apache/commons/collections4/map/CompositeMap.java new file mode 100644 index 0000000..89218ec --- /dev/null +++ b/src/org/apache/commons/collections4/map/CompositeMap.java @@ -0,0 +1,549 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.Serializable; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.collection.CompositeCollection; +import org.apache.commons.collections4.set.CompositeSet; + +/** + * Decorates a map of other maps to provide a single unified view. + *

              + * Changes made to this map will actually be made on the decorated map. + * Add and remove operations require the use of a pluggable strategy. If no + * strategy is provided then add and remove are unsupported. + *

              + * Note that CompositeMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 3.0 + * @version $Id: CompositeMap.java 1612021 2014-07-20 04:51:05Z ggregory $ + */ +public class CompositeMap extends AbstractIterableMap implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = -6096931280583808322L; + + /** Array of all maps in the composite */ + private Map[] composite; + + /** Handle mutation operations */ + private MapMutator mutator; + + /** + * Create a new, empty, CompositeMap. + */ + @SuppressWarnings("unchecked") + public CompositeMap() { + this(new Map[] {}, null); + } + + /** + * Create a new CompositeMap with two composited Map instances. + * + * @param one the first Map to be composited + * @param two the second Map to be composited + * @throws IllegalArgumentException if there is a key collision + */ + @SuppressWarnings("unchecked") + public CompositeMap(final Map one, final Map two) { + this(new Map[] { one, two }, null); + } + + /** + * Create a new CompositeMap with two composited Map instances. + * + * @param one the first Map to be composited + * @param two the second Map to be composited + * @param mutator MapMutator to be used for mutation operations + */ + @SuppressWarnings("unchecked") + public CompositeMap(final Map one, final Map two, final MapMutator mutator) { + this(new Map[] { one, two }, mutator); + } + + /** + * Create a new CompositeMap which composites all of the Map instances in the + * argument. It copies the argument array, it does not use it directly. + * + * @param composite the Maps to be composited + * @throws IllegalArgumentException if there is a key collision + */ + @SafeVarargs + public CompositeMap(final Map... composite) { + this(composite, null); + } + + /** + * Create a new CompositeMap which composites all of the Map instances in the + * argument. It copies the argument array, it does not use it directly. + * + * @param composite Maps to be composited + * @param mutator MapMutator to be used for mutation operations + */ + @SuppressWarnings("unchecked") + public CompositeMap(final Map[] composite, final MapMutator mutator) { + this.mutator = mutator; + this.composite = new Map[0]; + for (int i = composite.length - 1; i >= 0; --i) { + this.addComposited(composite[i]); + } + } + + //----------------------------------------------------------------------- + /** + * Specify the MapMutator to be used by mutation operations. + * + * @param mutator the MapMutator to be used for mutation delegation + */ + public void setMutator(final MapMutator mutator) { + this.mutator = mutator; + } + + /** + * Add an additional Map to the composite. + * + * @param map the Map to be added to the composite + * @throws IllegalArgumentException if there is a key collision and there is no + * MapMutator set to handle it. + */ + @SuppressWarnings("unchecked") + public synchronized void addComposited(final Map map) throws IllegalArgumentException { + for (int i = composite.length - 1; i >= 0; --i) { + final Collection intersect = CollectionUtils.intersection(this.composite[i].keySet(), map.keySet()); + if (intersect.size() != 0) { + if (this.mutator == null) { + throw new IllegalArgumentException("Key collision adding Map to CompositeMap"); + } + this.mutator.resolveCollision(this, this.composite[i], map, intersect); + } + } + final Map[] temp = new Map[this.composite.length + 1]; + System.arraycopy(this.composite, 0, temp, 0, this.composite.length); + temp[temp.length - 1] = map; + this.composite = temp; + } + + /** + * Remove a Map from the composite. + * + * @param map the Map to be removed from the composite + * @return The removed Map or null if map is not in the composite + */ + @SuppressWarnings("unchecked") + public synchronized Map removeComposited(final Map map) { + final int size = this.composite.length; + for (int i = 0; i < size; ++i) { + if (this.composite[i].equals(map)) { + final Map[] temp = new Map[size - 1]; + System.arraycopy(this.composite, 0, temp, 0, i); + System.arraycopy(this.composite, i + 1, temp, i, size - i - 1); + this.composite = temp; + return map; + } + } + return null; + } + + //----------------------------------------------------------------------- + /** + * Calls clear() on all composited Maps. + * + * @throws UnsupportedOperationException if any of the composited Maps do not support clear() + */ + public void clear() { + for (int i = this.composite.length - 1; i >= 0; --i) { + this.composite[i].clear(); + } + } + + /** + * Returns {@code true} if this map contains a mapping for the specified + * key. More formally, returns {@code true} if and only if + * this map contains at a mapping for a key {@code k} such that + * {@code (key==null ? k==null : key.equals(k))}. (There can be + * at most one such mapping.) + * + * @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 key is of an inappropriate type for + * this map (optional). + * @throws NullPointerException if the key is {@code null} and this map + * does not not permit {@code null} keys (optional). + */ + public boolean containsKey(final Object key) { + for (int i = this.composite.length - 1; i >= 0; --i) { + if (this.composite[i].containsKey(key)) { + return true; + } + } + return false; + } + + /** + * 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 of the {@code Map} interface. + * + * @param value value whose presence in this map is to be tested. + * @return {@code true} if this map maps one or more keys to the + * specified value. + * @throws ClassCastException if the value is of an inappropriate type for + * this map (optional). + * @throws NullPointerException if the value is {@code null} and this map + * does not not permit {@code null} values (optional). + */ + public boolean containsValue(final Object value) { + for (int i = this.composite.length - 1; i >= 0; --i) { + if (this.composite[i].containsValue(value)) { + return true; + } + } + return false; + } + + /** + * Returns a set view of the mappings contained in this map. Each element + * in the returned set is a Map.Entry. 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, + * 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. + *

              + * This implementation returns a CompositeSet which + * composites the entry sets from all of the composited maps. + * + * @see CompositeSet + * @return a set view of the mappings contained in this map. + */ + public Set> entrySet() { + final CompositeSet> entries = new CompositeSet>(); + for (int i = composite.length - 1; i >= 0; --i) { + entries.addComposited(composite[i].entrySet()); + } + return entries; + } + + /** + * Returns the value to which this map maps the specified key. Returns + * {@code null} if the map contains no mapping for this key. 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 {@code containsKey} + * operation may be used to distinguish these two cases. + * + *

              More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that (key==null ? k==null : + * key.equals(k)), then this method returns {@code v}; otherwise + * it returns {@code null}. (There can be at most one such mapping.) + * + * @param key key whose associated value is to be returned. + * @return the value to which this map maps the specified key, or + * {@code null} if the map contains no mapping for this key. + * + * @throws ClassCastException if the key is of an inappropriate type for + * this map (optional). + * @throws NullPointerException key is {@code null} and this map does not + * not permit {@code null} keys (optional). + * + * @see #containsKey(Object) + */ + public V get(final Object key) { + for (int i = this.composite.length - 1; i >= 0; --i) { + if (this.composite[i].containsKey(key)) { + return this.composite[i].get(key); + } + } + return null; + } + + /** + * Returns {@code true} if this map contains no key-value mappings. + * + * @return {@code true} if this map contains no key-value mappings. + */ + public boolean isEmpty() { + for (int i = this.composite.length - 1; i >= 0; --i) { + if (!this.composite[i].isEmpty()) { + return false; + } + } + return true; + } + + /** + * Returns a set view of the keys contained in this map. 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, 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 add or {@code addAll} operations. + *

              + * This implementation returns a CompositeSet which + * composites the key sets from all of the composited maps. + * + * @return a set view of the keys contained in this map. + */ + public Set keySet() { + final CompositeSet keys = new CompositeSet(); + for (int i = this.composite.length - 1; i >= 0; --i) { + keys.addComposited(this.composite[i].keySet()); + } + return keys; + } + + /** + * Associates the specified value with the specified key in this map + * (optional operation). If the map previously contained a mapping for + * this key, the old value is replaced by the specified value. (A map + * {@code m} is said to contain a mapping for a key {@code k} if and only + * if {@link #containsKey(Object) m.containsKey(k)} would return + * {@code true}.)) + * + * @param key key with which the specified value is to be associated. + * @param value value to be associated with the specified key. + * @return previous value associated with specified key, or {@code null} + * if there was no mapping for key. A {@code null} return can + * also indicate that the map previously associated {@code null} + * with the specified key, if the implementation supports + * {@code null} values. + * + * @throws UnsupportedOperationException if no MapMutator has been specified + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map. + * @throws IllegalArgumentException if some aspect of this key or value + * prevents it from being stored in this map. + * @throws NullPointerException this map does not permit {@code null} + * keys or values, and the specified key or value is + * {@code null}. + */ + public V put(final K key, final V value) { + if (this.mutator == null) { + throw new UnsupportedOperationException("No mutator specified"); + } + return this.mutator.put(this, this.composite, key, value); + } + + /** + * Copies all of the mappings from the specified map to this map + * (optional operation). The effect of this call is equivalent to that + * of calling {@link #put(Object,Object) put(k, v)} on this map once + * for each mapping from key {@code k} to value {@code v} in the + * specified map. The behavior of this operation is unspecified if the + * specified map is modified while the operation is in progress. + * + * @param map Mappings to be stored in this map. + * + * @throws UnsupportedOperationException if the {@code putAll} method is + * not supported by 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 IllegalArgumentException some aspect of a key or value in the + * specified map prevents it from being stored in this map. + * @throws NullPointerException the specified map is {@code null}, or if + * this map does not permit {@code null} keys or values, and the + * specified map contains {@code null} keys or values. + */ + public void putAll(final Map map) { + if (this.mutator == null) { + throw new UnsupportedOperationException("No mutator specified"); + } + this.mutator.putAll(this, this.composite, map); + } + + /** + * Removes the mapping for this key from this map if it is present + * (optional operation). More formally, if this map contains a mapping + * from key {@code k} to value {@code v} such that + * (key==null ? k==null : key.equals(k)), that mapping + * is removed. (The map can contain at most one such mapping.) + * + *

              Returns the value to which the map previously associated the key, or + * {@code null} if the map contained no mapping for this key. (A + * {@code null} return can also indicate that the map previously + * associated {@code null} with the specified key if the implementation + * supports {@code null} values.) The map will not contain a mapping for + * the specified key once the call returns. + * + * @param key key whose mapping is to be removed from the map. + * @return previous value associated with specified key, or {@code null} + * if there was no mapping for key. + * + * @throws ClassCastException if the key is of an inappropriate type for + * the composited map (optional). + * @throws NullPointerException if the key is {@code null} and the composited map + * does not not permit {@code null} keys (optional). + * @throws UnsupportedOperationException if the {@code remove} method is + * not supported by the composited map containing the key + */ + public V remove(final Object key) { + for (int i = this.composite.length - 1; i >= 0; --i) { + if (this.composite[i].containsKey(key)) { + return this.composite[i].remove(key); + } + } + return null; + } + + /** + * Returns the number of key-value mappings in this map. If the + * map contains more than {@code Integer.MAX_VALUE} elements, returns + * {@code Integer.MAX_VALUE}. + * + * @return the number of key-value mappings in this map. + */ + public int size() { + int size = 0; + for (int i = this.composite.length - 1; i >= 0; --i) { + size += this.composite[i].size(); + } + return size; + } + + /** + * Returns a collection view of the values contained in this map. 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, 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 add or {@code addAll} operations. + * + * @return a collection view of the values contained in this map. + */ + public Collection values() { + final CompositeCollection values = new CompositeCollection(); + for (int i = composite.length - 1; i >= 0; --i) { + values.addComposited(composite[i].values()); + } + return values; + } + + /** + * Checks if this Map equals another as per the Map specification. + * + * @param obj the object to compare to + * @return true if the maps are equal + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof Map) { + final Map map = (Map) obj; + return this.entrySet().equals(map.entrySet()); + } + return false; + } + + /** + * Gets a hash code for the Map as per the Map specification. + * {@inheritDoc} + */ + @Override + public int hashCode() { + int code = 0; + for (final Map.Entry entry : entrySet()) { + code += entry.hashCode(); + } + return code; + } + + /** + * This interface allows definition for all of the indeterminate + * mutators in a CompositeMap, as well as providing a hook for + * callbacks on key collisions. + */ + public static interface MapMutator extends Serializable { + /** + * Called when adding a new Composited Map results in a + * key collision. + * + * @param composite the CompositeMap with the collision + * @param existing the Map already in the composite which contains the + * offending key + * @param added the Map being added + * @param intersect the intersection of the keysets of the existing and added maps + */ + void resolveCollision(CompositeMap composite, Map existing, + Map added, Collection intersect); + + /** + * Called when the CompositeMap.put() method is invoked. + * + * @param map the CompositeMap which is being modified + * @param composited array of Maps in the CompositeMap being modified + * @param key key with which the specified value is to be associated. + * @param value value to be associated with the specified key. + * @return previous value associated with specified key, or {@code null} + * if there was no mapping for key. A {@code null} return can + * also indicate that the map previously associated {@code null} + * with the specified key, if the implementation supports + * {@code null} values. + * + * @throws UnsupportedOperationException if not defined + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map. + * @throws IllegalArgumentException if some aspect of this key or value + * prevents it from being stored in this map. + * @throws NullPointerException this map does not permit {@code null} + * keys or values, and the specified key or value is + * {@code null}. + */ + V put(CompositeMap map, Map[] composited, K key, V value); + + /** + * Called when the CompositeMap.putAll() method is invoked. + * + * @param map the CompositeMap which is being modified + * @param composited array of Maps in the CompositeMap being modified + * @param mapToAdd Mappings to be stored in this CompositeMap + * + * @throws UnsupportedOperationException if not defined + * @throws ClassCastException if the class of the specified key or value + * prevents it from being stored in this map. + * @throws IllegalArgumentException if some aspect of this key or value + * prevents it from being stored in this map. + * @throws NullPointerException this map does not permit {@code null} + * keys or values, and the specified key or value is + * {@code null}. + */ + void putAll(CompositeMap map, Map[] composited, + Map mapToAdd); + } +} diff --git a/src/org/apache/commons/collections4/map/DefaultedMap.java b/src/org/apache/commons/collections4/map/DefaultedMap.java new file mode 100644 index 0000000..7318b73 --- /dev/null +++ b/src/org/apache/commons/collections4/map/DefaultedMap.java @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.functors.ConstantTransformer; +import org.apache.commons.collections4.functors.FactoryTransformer; + +/** + * Decorates another Map returning a default value if the map + * does not contain the requested key. + *

              + * When the {@link #get(Object)} method is called with a key that does not + * exist in the map, this map will return the default value specified in + * the constructor/factory. Only the get method is altered, so the + * {@link Map#containsKey(Object)} can be used to determine if a key really + * is in the map or not. + *

              + * The defaulted value is not added to the map. + * Compare this behaviour with {@link LazyMap}, which does add the value + * to the map (via a Transformer). + *

              + * For instance: + *

              + * Map map = new DefaultedMap("NULL");
              + * Object obj = map.get("Surname");
              + * // obj == "NULL"
              + * 
              + * After the above code is executed the map is still empty. + *

              + * Note that DefaultedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 3.2 + * @version $Id: DefaultedMap.java 1686855 2015-06-22 13:00:27Z tn $ + * + * @see LazyMap + */ +public class DefaultedMap extends AbstractMapDecorator implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 19698628745827L; + + /** The transformer to use if the map does not contain a key */ + private final Transformer value; + + //----------------------------------------------------------------------- + /** + * Factory method to create a defaulting map. + *

              + * The value specified is returned when a missing key is found. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param defaultValue the default value to return when the key is not found + * @return a new defaulting map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static DefaultedMap defaultedMap(final Map map, final V defaultValue) { + return new DefaultedMap(map, ConstantTransformer.constantTransformer(defaultValue)); + } + + /** + * Factory method to create a defaulting map. + *

              + * The factory specified is called when a missing key is found. + * The result will be returned as the result of the map get(key) method. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param factory the factory to use to create entries, must not be null + * @return a new defaulting map + * @throws NullPointerException if map or factory is null + * @since 4.0 + */ + public static DefaultedMap defaultedMap(final Map map, final Factory factory) { + if (factory == null) { + throw new IllegalArgumentException("Factory must not be null"); + } + return new DefaultedMap(map, FactoryTransformer.factoryTransformer(factory)); + } + + /** + * Factory method to create a defaulting map. + *

              + * The transformer specified is called when a missing key is found. + * The key is passed to the transformer as the input, and the result + * will be returned as the result of the map get(key) method. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param transformer the transformer to use as a factory to create entries, must not be null + * @return a new defaulting map + * @throws NullPointerException if map or factory is null + * @since 4.0 + */ + public static Map defaultedMap(final Map map, + final Transformer transformer) { + if (transformer == null) { + throw new IllegalArgumentException("Transformer must not be null"); + } + return new DefaultedMap(map, transformer); + } + + //----------------------------------------------------------------------- + /** + * Constructs a new empty DefaultedMap that decorates + * a HashMap. + *

              + * The object passed in will be returned by the map whenever an + * unknown key is requested. + * + * @param defaultValue the default value to return when the key is not found + */ + public DefaultedMap(final V defaultValue) { + this(ConstantTransformer.constantTransformer(defaultValue)); + } + + /** + * Constructs a new empty DefaultedMap that decorates a HashMap. + * + * @param defaultValueTransformer transformer to use to generate missing values. + */ + public DefaultedMap(final Transformer defaultValueTransformer) { + this(new HashMap(), defaultValueTransformer); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param defaultValueTransformer the value transformer to use + * @throws NullPointerException if map or transformer is null + */ + protected DefaultedMap(final Map map, final Transformer defaultValueTransformer) { + super(map); + if (defaultValueTransformer == null) { + throw new NullPointerException("Transformer must not be null."); + } + this.value = defaultValueTransformer; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); + } + + //----------------------------------------------------------------------- + @Override + @SuppressWarnings("unchecked") + public V get(final Object key) { + // create value for key if key is not currently in the map + if (map.containsKey(key) == false) { + return value.transform((K) key); + } + return map.get(key); + } + + // no need to wrap keySet, entrySet or values as they are views of + // existing map entries - you can't do a map-style get on them. +} diff --git a/src/org/apache/commons/collections4/map/EntrySetToMapIteratorAdapter.java b/src/org/apache/commons/collections4/map/EntrySetToMapIteratorAdapter.java new file mode 100644 index 0000000..8623d1d --- /dev/null +++ b/src/org/apache/commons/collections4/map/EntrySetToMapIteratorAdapter.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.ResettableIterator; + +/** + * Adapts a Map entrySet to the MapIterator interface. + * + * @since 4.0 + * @version $Id: EntrySetToMapIteratorAdapter.java 1494296 2013-06-18 20:54:29Z tn $ + */ +public class EntrySetToMapIteratorAdapter implements MapIterator, ResettableIterator { + + /** The adapted Map entry Set. */ + Set> entrySet; + + /** The resettable iterator in use. */ + transient Iterator> iterator; + + /** The currently positioned Map entry. */ + transient Map.Entry entry; + + /** + * Create a new EntrySetToMapIteratorAdapter. + * @param entrySet the entrySet to adapt + */ + public EntrySetToMapIteratorAdapter(final Set> entrySet) { + this.entrySet = entrySet; + reset(); + } + + /** + * {@inheritDoc} + */ + public K getKey() { + return current().getKey(); + } + + /** + * {@inheritDoc} + */ + public V getValue() { + return current().getValue(); + } + + /** + * {@inheritDoc} + */ + public V setValue(final V value) { + return current().setValue(value); + } + + /** + * {@inheritDoc} + */ + public boolean hasNext() { + return iterator.hasNext(); + } + + /** + * {@inheritDoc} + */ + public K next() { + entry = iterator.next(); + return getKey(); + } + + /** + * {@inheritDoc} + */ + public synchronized void reset() { + iterator = entrySet.iterator(); + } + + /** + * {@inheritDoc} + */ + public void remove() { + iterator.remove(); + entry = null; + } + + /** + * Get the currently active entry. + * @return Map.Entry + */ + protected synchronized Map.Entry current() { + if (entry == null) { + throw new IllegalStateException(); + } + return entry; + } +} diff --git a/src/org/apache/commons/collections4/map/FixedSizeMap.java b/src/org/apache/commons/collections4/map/FixedSizeMap.java new file mode 100644 index 0000000..aff54ae --- /dev/null +++ b/src/org/apache/commons/collections4/map/FixedSizeMap.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.BoundedMap; +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another Map to fix the size, preventing add/remove. + *

              + * Any action that would change the size of the map is disallowed. + * The put method is allowed to change the value associated with an existing + * key however. + *

              + * If trying to remove or clear the map, an UnsupportedOperationException is + * thrown. If trying to put a new mapping into the map, an + * IllegalArgumentException is thrown. This is because the put method can + * succeed if the mapping's key already exists in the map, so the put method + * is not always unsupported. + *

              + * Note that FixedSizeMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: FixedSizeMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class FixedSizeMap + extends AbstractMapDecorator + implements BoundedMap, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 7450927208116179316L; + + /** + * Factory method to create a fixed size map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return a new fixed size map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static FixedSizeMap fixedSizeMap(final Map map) { + return new FixedSizeMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + protected FixedSizeMap(final Map map) { + super(map); + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + //----------------------------------------------------------------------- + @Override + public V put(final K key, final V value) { + if (map.containsKey(key) == false) { + throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size"); + } + return map.put(key, value); + } + + @Override + public void putAll(final Map mapToCopy) { + for (final K key : mapToCopy.keySet()) { + if (!containsKey(key)) { + throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size"); + } + } + map.putAll(mapToCopy); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("Map is fixed size"); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException("Map is fixed size"); + } + + @Override + public Set> entrySet() { + final Set> set = map.entrySet(); + // unmodifiable set will still allow modification via Map.Entry objects + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Set keySet() { + final Set set = map.keySet(); + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Collection values() { + final Collection coll = map.values(); + return UnmodifiableCollection.unmodifiableCollection(coll); + } + + public boolean isFull() { + return true; + } + + public int maxSize() { + return size(); + } + +} diff --git a/src/org/apache/commons/collections4/map/FixedSizeSortedMap.java b/src/org/apache/commons/collections4/map/FixedSizeSortedMap.java new file mode 100644 index 0000000..efdf104 --- /dev/null +++ b/src/org/apache/commons/collections4/map/FixedSizeSortedMap.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.apache.commons.collections4.BoundedMap; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another SortedMap to fix the size blocking add/remove. + *

              + * Any action that would change the size of the map is disallowed. + * The put method is allowed to change the value associated with an existing + * key however. + *

              + * If trying to remove or clear the map, an UnsupportedOperationException is + * thrown. If trying to put a new mapping into the map, an + * IllegalArgumentException is thrown. This is because the put method can + * succeed if the mapping's key already exists in the map, so the put method + * is not always unsupported. + *

              + * Note that FixedSizeSortedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedSortedMap}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: FixedSizeSortedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class FixedSizeSortedMap + extends AbstractSortedMapDecorator + implements BoundedMap, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 3126019624511683653L; + + /** + * Factory method to create a fixed size sorted map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return a new fixed size sorted map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static FixedSizeSortedMap fixedSizeSortedMap(final SortedMap map) { + return new FixedSizeSortedMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + protected FixedSizeSortedMap(final SortedMap map) { + super(map); + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + protected SortedMap getSortedMap() { + return (SortedMap) map; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + //----------------------------------------------------------------------- + @Override + public V put(final K key, final V value) { + if (map.containsKey(key) == false) { + throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size"); + } + return map.put(key, value); + } + + @Override + public void putAll(final Map mapToCopy) { + if (CollectionUtils.isSubCollection(mapToCopy.keySet(), keySet())) { + throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size"); + } + map.putAll(mapToCopy); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("Map is fixed size"); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException("Map is fixed size"); + } + + @Override + public Set> entrySet() { + return UnmodifiableSet.unmodifiableSet(map.entrySet()); + } + + @Override + public Set keySet() { + return UnmodifiableSet.unmodifiableSet(map.keySet()); + } + + @Override + public Collection values() { + return UnmodifiableCollection.unmodifiableCollection(map.values()); + } + + //----------------------------------------------------------------------- + @Override + public SortedMap subMap(final K fromKey, final K toKey) { + return new FixedSizeSortedMap(getSortedMap().subMap(fromKey, toKey)); + } + + @Override + public SortedMap headMap(final K toKey) { + return new FixedSizeSortedMap(getSortedMap().headMap(toKey)); + } + + @Override + public SortedMap tailMap(final K fromKey) { + return new FixedSizeSortedMap(getSortedMap().tailMap(fromKey)); + } + + public boolean isFull() { + return true; + } + + public int maxSize() { + return size(); + } + +} diff --git a/src/org/apache/commons/collections4/map/Flat3Map.java b/src/org/apache/commons/collections4/map/Flat3Map.java new file mode 100644 index 0000000..b6fa63e --- /dev/null +++ b/src/org/apache/commons/collections4/map/Flat3Map.java @@ -0,0 +1,1249 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.apache.commons.collections4.IterableMap; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.ResettableIterator; +import org.apache.commons.collections4.iterators.EmptyIterator; +import org.apache.commons.collections4.iterators.EmptyMapIterator; + +/** + * A Map implementation that stores data in simple fields until + * the size is greater than 3. + *

              + * This map is designed for performance and can outstrip HashMap. + * It also has good garbage collection characteristics. + *

                + *
              • Optimised for operation at size 3 or less. + *
              • Still works well once size 3 exceeded. + *
              • Gets at size 3 or less are about 0-10% faster than HashMap, + *
              • Puts at size 3 or less are over 4 times faster than HashMap. + *
              • Performance 5% slower than HashMap once size 3 exceeded once. + *
              + * The design uses two distinct modes of operation - flat and delegate. + * While the map is size 3 or less, operations map straight onto fields using + * switch statements. Once size 4 is reached, the map switches to delegate mode + * and only switches back when cleared. In delegate mode, all operations are + * forwarded straight to a HashMap resulting in the 5% performance loss. + *

              + * The performance gains on puts are due to not needing to create a Map Entry + * object. This is a large saving not only in performance but in garbage collection. + *

              + * Whilst in flat mode this map is also easy for the garbage collector to dispatch. + * This is because it contains no complex objects or arrays which slow the progress. + *

              + * Do not use Flat3Map if the size is likely to grow beyond 3. + *

              + * Note that Flat3Map is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 3.0 + * @version $Id: Flat3Map.java 1477799 2013-04-30 19:56:11Z tn $ + */ +public class Flat3Map implements IterableMap, Serializable, Cloneable { + + /** Serialization version */ + private static final long serialVersionUID = -6701087419741928296L; + + /** The size of the map, used while in flat mode */ + private transient int size; + /** Hash, used while in flat mode */ + private transient int hash1; + /** Hash, used while in flat mode */ + private transient int hash2; + /** Hash, used while in flat mode */ + private transient int hash3; + /** Key, used while in flat mode */ + private transient K key1; + /** Key, used while in flat mode */ + private transient K key2; + /** Key, used while in flat mode */ + private transient K key3; + /** Value, used while in flat mode */ + private transient V value1; + /** Value, used while in flat mode */ + private transient V value2; + /** Value, used while in flat mode */ + private transient V value3; + /** Map, used while in delegate mode */ + private transient AbstractHashedMap delegateMap; + + /** + * Constructor. + */ + public Flat3Map() { + super(); + } + + /** + * Constructor copying elements from another map. + * + * @param map the map to copy + * @throws NullPointerException if the map is null + */ + public Flat3Map(final Map map) { + super(); + putAll(map); + } + + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the key specified. + * + * @param key the key + * @return the mapped value, null if no match + */ + public V get(final Object key) { + if (delegateMap != null) { + return delegateMap.get(key); + } + if (key == null) { + switch (size) { + // drop through + case 3: + if (key3 == null) { + return value3; + } + case 2: + if (key2 == null) { + return value2; + } + case 1: + if (key1 == null) { + return value1; + } + } + } else { + if (size > 0) { + final int hashCode = key.hashCode(); + switch (size) { + // drop through + case 3: + if (hash3 == hashCode && key.equals(key3)) { + return value3; + } + case 2: + if (hash2 == hashCode && key.equals(key2)) { + return value2; + } + case 1: + if (hash1 == hashCode && key.equals(key1)) { + return value1; + } + } + } + } + return null; + } + + /** + * Gets the size of the map. + * + * @return the size + */ + public int size() { + if (delegateMap != null) { + return delegateMap.size(); + } + return size; + } + + /** + * Checks whether the map is currently empty. + * + * @return true if the map is currently size zero + */ + public boolean isEmpty() { + return size() == 0; + } + + //----------------------------------------------------------------------- + /** + * Checks whether the map contains the specified key. + * + * @param key the key to search for + * @return true if the map contains the key + */ + public boolean containsKey(final Object key) { + if (delegateMap != null) { + return delegateMap.containsKey(key); + } + if (key == null) { + switch (size) { // drop through + case 3: + if (key3 == null) { + return true; + } + case 2: + if (key2 == null) { + return true; + } + case 1: + if (key1 == null) { + return true; + } + } + } else { + if (size > 0) { + final int hashCode = key.hashCode(); + switch (size) { // drop through + case 3: + if (hash3 == hashCode && key.equals(key3)) { + return true; + } + case 2: + if (hash2 == hashCode && key.equals(key2)) { + return true; + } + case 1: + if (hash1 == hashCode && key.equals(key1)) { + return true; + } + } + } + } + return false; + } + + /** + * Checks whether the map contains the specified value. + * + * @param value the value to search for + * @return true if the map contains the key + */ + public boolean containsValue(final Object value) { + if (delegateMap != null) { + return delegateMap.containsValue(value); + } + if (value == null) { // drop through + switch (size) { + case 3: + if (value3 == null) { + return true; + } + case 2: + if (value2 == null) { + return true; + } + case 1: + if (value1 == null) { + return true; + } + } + } else { + switch (size) { // drop through + case 3: + if (value.equals(value3)) { + return true; + } + case 2: + if (value.equals(value2)) { + return true; + } + case 1: + if (value.equals(value1)) { + return true; + } + } + } + return false; + } + + //----------------------------------------------------------------------- + /** + * Puts a key-value mapping into this map. + * + * @param key the key to add + * @param value the value to add + * @return the value previously mapped to this key, null if none + */ + public V put(final K key, final V value) { + if (delegateMap != null) { + return delegateMap.put(key, value); + } + // change existing mapping + if (key == null) { + switch (size) { // drop through + case 3: + if (key3 == null) { + final V old = value3; + value3 = value; + return old; + } + case 2: + if (key2 == null) { + final V old = value2; + value2 = value; + return old; + } + case 1: + if (key1 == null) { + final V old = value1; + value1 = value; + return old; + } + } + } else { + if (size > 0) { + final int hashCode = key.hashCode(); + switch (size) { // drop through + case 3: + if (hash3 == hashCode && key.equals(key3)) { + final V old = value3; + value3 = value; + return old; + } + case 2: + if (hash2 == hashCode && key.equals(key2)) { + final V old = value2; + value2 = value; + return old; + } + case 1: + if (hash1 == hashCode && key.equals(key1)) { + final V old = value1; + value1 = value; + return old; + } + } + } + } + + // add new mapping + switch (size) { + default: + convertToMap(); + delegateMap.put(key, value); + return null; + case 2: + hash3 = key == null ? 0 : key.hashCode(); + key3 = key; + value3 = value; + break; + case 1: + hash2 = key == null ? 0 : key.hashCode(); + key2 = key; + value2 = value; + break; + case 0: + hash1 = key == null ? 0 : key.hashCode(); + key1 = key; + value1 = value; + break; + } + size++; + return null; + } + + /** + * Puts all the values from the specified map into this map. + * + * @param map the map to add + * @throws NullPointerException if the map is null + */ + public void putAll(final Map map) { + final int size = map.size(); + if (size == 0) { + return; + } + if (delegateMap != null) { + delegateMap.putAll(map); + return; + } + if (size < 4) { + for (final Map.Entry entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } else { + convertToMap(); + delegateMap.putAll(map); + } + } + + /** + * Converts the flat map data to a map. + */ + private void convertToMap() { + delegateMap = createDelegateMap(); + switch (size) { // drop through + case 3: + delegateMap.put(key3, value3); + case 2: + delegateMap.put(key2, value2); + case 1: + delegateMap.put(key1, value1); + case 0: + break; + default: + throw new IllegalStateException("Invalid map index: " + size); + } + + size = 0; + hash1 = hash2 = hash3 = 0; + key1 = key2 = key3 = null; + value1 = value2 = value3 = null; + } + + /** + * Create an instance of the map used for storage when in delegation mode. + *

              + * This can be overridden by subclasses to provide a different map implementation. + * Not every AbstractHashedMap is suitable, identity and reference based maps + * would be poor choices. + * + * @return a new AbstractHashedMap or subclass + * @since 3.1 + */ + protected AbstractHashedMap createDelegateMap() { + return new HashedMap(); + } + + /** + * Removes the specified mapping from this map. + * + * @param key the mapping to remove + * @return the value mapped to the removed key, null if key not in map + */ + public V remove(final Object key) { + if (delegateMap != null) { + return delegateMap.remove(key); + } + if (size == 0) { + return null; + } + if (key == null) { + switch (size) { // drop through + case 3: + if (key3 == null) { + final V old = value3; + hash3 = 0; + key3 = null; + value3 = null; + size = 2; + return old; + } + if (key2 == null) { + final V old = value2; + hash2 = hash3; + key2 = key3; + value2 = value3; + hash3 = 0; + key3 = null; + value3 = null; + size = 2; + return old; + } + if (key1 == null) { + final V old = value1; + hash1 = hash3; + key1 = key3; + value1 = value3; + hash3 = 0; + key3 = null; + value3 = null; + size = 2; + return old; + } + return null; + case 2: + if (key2 == null) { + final V old = value2; + hash2 = 0; + key2 = null; + value2 = null; + size = 1; + return old; + } + if (key1 == null) { + final V old = value1; + hash1 = hash2; + key1 = key2; + value1 = value2; + hash2 = 0; + key2 = null; + value2 = null; + size = 1; + return old; + } + return null; + case 1: + if (key1 == null) { + final V old = value1; + hash1 = 0; + key1 = null; + value1 = null; + size = 0; + return old; + } + } + } else { + if (size > 0) { + final int hashCode = key.hashCode(); + switch (size) { // drop through + case 3: + if (hash3 == hashCode && key.equals(key3)) { + final V old = value3; + hash3 = 0; + key3 = null; + value3 = null; + size = 2; + return old; + } + if (hash2 == hashCode && key.equals(key2)) { + final V old = value2; + hash2 = hash3; + key2 = key3; + value2 = value3; + hash3 = 0; + key3 = null; + value3 = null; + size = 2; + return old; + } + if (hash1 == hashCode && key.equals(key1)) { + final V old = value1; + hash1 = hash3; + key1 = key3; + value1 = value3; + hash3 = 0; + key3 = null; + value3 = null; + size = 2; + return old; + } + return null; + case 2: + if (hash2 == hashCode && key.equals(key2)) { + final V old = value2; + hash2 = 0; + key2 = null; + value2 = null; + size = 1; + return old; + } + if (hash1 == hashCode && key.equals(key1)) { + final V old = value1; + hash1 = hash2; + key1 = key2; + value1 = value2; + hash2 = 0; + key2 = null; + value2 = null; + size = 1; + return old; + } + return null; + case 1: + if (hash1 == hashCode && key.equals(key1)) { + final V old = value1; + hash1 = 0; + key1 = null; + value1 = null; + size = 0; + return old; + } + } + } + } + return null; + } + + /** + * Clears the map, resetting the size to zero and nullifying references + * to avoid garbage collection issues. + */ + public void clear() { + if (delegateMap != null) { + delegateMap.clear(); // should aid gc + delegateMap = null; // switch back to flat mode + } else { + size = 0; + hash1 = hash2 = hash3 = 0; + key1 = key2 = key3 = null; + value1 = value2 = value3 = null; + } + } + + //----------------------------------------------------------------------- + /** + * Gets an iterator over the map. + * Changes made to the iterator affect this map. + *

              + * A MapIterator returns the keys in the map. It also provides convenient + * methods to get the key and value, and set the value. + * It avoids the need to create an entrySet/keySet/values object. + * It also avoids creating the Map Entry object. + * + * @return the map iterator + */ + public MapIterator mapIterator() { + if (delegateMap != null) { + return delegateMap.mapIterator(); + } + if (size == 0) { + return EmptyMapIterator.emptyMapIterator(); + } + return new FlatMapIterator(this); + } + + /** + * FlatMapIterator + */ + static class FlatMapIterator implements MapIterator, ResettableIterator { + private final Flat3Map parent; + private int nextIndex = 0; + private boolean canRemove = false; + + FlatMapIterator(final Flat3Map parent) { + super(); + this.parent = parent; + } + + public boolean hasNext() { + return nextIndex < parent.size; + } + + public K next() { + if (hasNext() == false) { + throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY); + } + canRemove = true; + nextIndex++; + return getKey(); + } + + public void remove() { + if (canRemove == false) { + throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID); + } + parent.remove(getKey()); + nextIndex--; + canRemove = false; + } + + public K getKey() { + if (canRemove == false) { + throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID); + } + switch (nextIndex) { + case 3: + return parent.key3; + case 2: + return parent.key2; + case 1: + return parent.key1; + } + throw new IllegalStateException("Invalid map index: " + nextIndex); + } + + public V getValue() { + if (canRemove == false) { + throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID); + } + switch (nextIndex) { + case 3: + return parent.value3; + case 2: + return parent.value2; + case 1: + return parent.value1; + } + throw new IllegalStateException("Invalid map index: " + nextIndex); + } + + public V setValue(final V value) { + if (canRemove == false) { + throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID); + } + final V old = getValue(); + switch (nextIndex) { + case 3: + parent.value3 = value; + break; + case 2: + parent.value2 = value; + break; + case 1: + parent.value1 = value; + break; + default: + throw new IllegalStateException("Invalid map index: " + nextIndex); + } + return old; + } + + public void reset() { + nextIndex = 0; + canRemove = false; + } + + @Override + public String toString() { + if (canRemove) { + return "Iterator[" + getKey() + "=" + getValue() + "]"; + } + return "Iterator[]"; + } + } + + /** + * Gets the entrySet view of the map. + * Changes made to the view affect this map. + *

              + * NOTE: from 4.0, the returned Map Entry will be an independent object and will + * not change anymore as the iterator progresses. To avoid this additional object + * creation and simply iterate through the entries, use {@link #mapIterator()}. + * + * @return the entrySet view + */ + public Set> entrySet() { + if (delegateMap != null) { + return delegateMap.entrySet(); + } + return new EntrySet(this); + } + + /** + * EntrySet + */ + static class EntrySet extends AbstractSet> { + private final Flat3Map parent; + + EntrySet(final Flat3Map parent) { + super(); + this.parent = parent; + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public void clear() { + parent.clear(); + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + final Object key = entry.getKey(); + final boolean result = parent.containsKey(key); + parent.remove(key); + return result; + } + + @Override + public Iterator> iterator() { + if (parent.delegateMap != null) { + return parent.delegateMap.entrySet().iterator(); + } + if (parent.size() == 0) { + return EmptyIterator.>emptyIterator(); + } + return new EntrySetIterator(parent); + } + } + + static class FlatMapEntry implements Map.Entry { + private final Flat3Map parent; + private final int index; + private volatile boolean removed; + + public FlatMapEntry(final Flat3Map parent, final int index) { + this.parent = parent; + this.index = index; + this.removed = false; + } + + /** + * Used by the iterator that created this entry to indicate that + * {@link java.util.Iterator#remove()} has been called. + *

              + * As a consequence, all subsequent call to {@link #getKey()}, + * {@link #setValue(Object)} and {@link #getValue()} will fail. + * + * @param flag + */ + void setRemoved(final boolean flag) { + this.removed = flag; + } + + public K getKey() { + if (removed) { + throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID); + } + switch (index) { + case 3: + return parent.key3; + case 2: + return parent.key2; + case 1: + return parent.key1; + } + throw new IllegalStateException("Invalid map index: " + index); + } + + public V getValue() { + if (removed) { + throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID); + } + switch (index) { + case 3: + return parent.value3; + case 2: + return parent.value2; + case 1: + return parent.value1; + } + throw new IllegalStateException("Invalid map index: " + index); + } + + public V setValue(final V value) { + if (removed) { + throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID); + } + final V old = getValue(); + switch (index) { + case 3: + parent.value3 = value; + break; + case 2: + parent.value2 = value; + break; + case 1: + parent.value1 = value; + break; + default: + throw new IllegalStateException("Invalid map index: " + index); + } + return old; + } + + @Override + public boolean equals(final Object obj) { + if (removed) { + return false; + } + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry other = (Map.Entry) obj; + final Object key = getKey(); + final Object value = getValue(); + return (key == null ? other.getKey() == null : key.equals(other.getKey())) && + (value == null ? other.getValue() == null : value.equals(other.getValue())); + } + + @Override + public int hashCode() { + if (removed) { + return 0; + } + final Object key = getKey(); + final Object value = getValue(); + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + @Override + public String toString() { + if (!removed) { + return getKey() + "=" + getValue(); + } + return ""; + } + + } + + static abstract class EntryIterator { + private final Flat3Map parent; + private int nextIndex = 0; + private FlatMapEntry currentEntry = null; + + /** + * Create a new Flat3Map.EntryIterator. + */ + public EntryIterator(final Flat3Map parent) { + this.parent = parent; + } + + public boolean hasNext() { + return nextIndex < parent.size; + } + + public Map.Entry nextEntry() { + if (!hasNext()) { + throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY); + } + currentEntry = new FlatMapEntry(parent, ++nextIndex); + return currentEntry; + } + + public void remove() { + if (currentEntry == null) { + throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID); + } + currentEntry.setRemoved(true); + parent.remove(currentEntry.getKey()); + nextIndex--; + currentEntry = null; + } + + } + + /** + * EntrySetIterator and MapEntry + */ + static class EntrySetIterator extends EntryIterator implements Iterator> { + EntrySetIterator(final Flat3Map parent) { + super(parent); + } + + public Map.Entry next() { + return nextEntry(); + } + } + + /** + * Gets the keySet view of the map. + * Changes made to the view affect this map. + * To simply iterate through the keys, use {@link #mapIterator()}. + * + * @return the keySet view + */ + public Set keySet() { + if (delegateMap != null) { + return delegateMap.keySet(); + } + return new KeySet(this); + } + + /** + * KeySet + */ + static class KeySet extends AbstractSet { + private final Flat3Map parent; + + KeySet(final Flat3Map parent) { + super(); + this.parent = parent; + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public void clear() { + parent.clear(); + } + + @Override + public boolean contains(final Object key) { + return parent.containsKey(key); + } + + @Override + public boolean remove(final Object key) { + final boolean result = parent.containsKey(key); + parent.remove(key); + return result; + } + + @Override + public Iterator iterator() { + if (parent.delegateMap != null) { + return parent.delegateMap.keySet().iterator(); + } + if (parent.size() == 0) { + return EmptyIterator.emptyIterator(); + } + return new KeySetIterator(parent); + } + } + + /** + * KeySetIterator + */ + static class KeySetIterator extends EntryIterator implements Iterator{ + + @SuppressWarnings("unchecked") + KeySetIterator(final Flat3Map parent) { + super((Flat3Map) parent); + } + + public K next() { + return nextEntry().getKey(); + } + } + + /** + * Gets the values view of the map. + * Changes made to the view affect this map. + * To simply iterate through the values, use {@link #mapIterator()}. + * + * @return the values view + */ + public Collection values() { + if (delegateMap != null) { + return delegateMap.values(); + } + return new Values(this); + } + + /** + * Values + */ + static class Values extends AbstractCollection { + private final Flat3Map parent; + + Values(final Flat3Map parent) { + super(); + this.parent = parent; + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public void clear() { + parent.clear(); + } + + @Override + public boolean contains(final Object value) { + return parent.containsValue(value); + } + + @Override + public Iterator iterator() { + if (parent.delegateMap != null) { + return parent.delegateMap.values().iterator(); + } + if (parent.size() == 0) { + return EmptyIterator.emptyIterator(); + } + return new ValuesIterator(parent); + } + } + + /** + * ValuesIterator + */ + static class ValuesIterator extends EntryIterator implements Iterator { + + @SuppressWarnings("unchecked") + ValuesIterator(final Flat3Map parent) { + super((Flat3Map) parent); + } + + public V next() { + return nextEntry().getValue(); + } + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeInt(size()); + for (final MapIterator it = mapIterator(); it.hasNext();) { + out.writeObject(it.next()); // key + out.writeObject(it.getValue()); // value + } + } + + /** + * Read the map in using a custom routine. + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + final int count = in.readInt(); + if (count > 3) { + delegateMap = createDelegateMap(); + } + for (int i = count; i > 0; i--) { + put((K) in.readObject(), (V) in.readObject()); + } + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the keys or values. + * + * @return a shallow clone + * @since 3.1 + */ + @Override + @SuppressWarnings("unchecked") + public Flat3Map clone() { + try { + final Flat3Map cloned = (Flat3Map) super.clone(); + if (cloned.delegateMap != null) { + cloned.delegateMap = cloned.delegateMap.clone(); + } + return cloned; + } catch (final CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + /** + * Compares this map with another. + * + * @param obj the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (delegateMap != null) { + return delegateMap.equals(obj); + } + if (obj instanceof Map == false) { + return false; + } + final Map other = (Map) obj; + if (size != other.size()) { + return false; + } + if (size > 0) { + Object otherValue = null; + switch (size) { // drop through + case 3: + if (other.containsKey(key3) == false) { + return false; + } + otherValue = other.get(key3); + if (value3 == null ? otherValue != null : !value3.equals(otherValue)) { + return false; + } + case 2: + if (other.containsKey(key2) == false) { + return false; + } + otherValue = other.get(key2); + if (value2 == null ? otherValue != null : !value2.equals(otherValue)) { + return false; + } + case 1: + if (other.containsKey(key1) == false) { + return false; + } + otherValue = other.get(key1); + if (value1 == null ? otherValue != null : !value1.equals(otherValue)) { + return false; + } + } + } + return true; + } + + /** + * Gets the standard Map hashCode. + * + * @return the hash code defined in the Map interface + */ + @Override + public int hashCode() { + if (delegateMap != null) { + return delegateMap.hashCode(); + } + int total = 0; + switch (size) { // drop through + case 3: + total += hash3 ^ (value3 == null ? 0 : value3.hashCode()); + case 2: + total += hash2 ^ (value2 == null ? 0 : value2.hashCode()); + case 1: + total += hash1 ^ (value1 == null ? 0 : value1.hashCode()); + case 0: + break; + default: + throw new IllegalStateException("Invalid map index: " + size); + } + return total; + } + + /** + * Gets the map as a String. + * + * @return a string version of the map + */ + @Override + public String toString() { + if (delegateMap != null) { + return delegateMap.toString(); + } + if (size == 0) { + return "{}"; + } + final StringBuilder buf = new StringBuilder(128); + buf.append('{'); + switch (size) { // drop through + case 3: + buf.append(key3 == this ? "(this Map)" : key3); + buf.append('='); + buf.append(value3 == this ? "(this Map)" : value3); + buf.append(','); + case 2: + buf.append(key2 == this ? "(this Map)" : key2); + buf.append('='); + buf.append(value2 == this ? "(this Map)" : value2); + buf.append(','); + case 1: + buf.append(key1 == this ? "(this Map)" : key1); + buf.append('='); + buf.append(value1 == this ? "(this Map)" : value1); + break; + // case 0: has already been dealt with + default: + throw new IllegalStateException("Invalid map index: " + size); + } + buf.append('}'); + return buf.toString(); + } + +} diff --git a/src/org/apache/commons/collections4/map/HashedMap.java b/src/org/apache/commons/collections4/map/HashedMap.java new file mode 100644 index 0000000..3e42287 --- /dev/null +++ b/src/org/apache/commons/collections4/map/HashedMap.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +/** + * A Map implementation that is a general purpose alternative + * to HashMap. + *

              + * This implementation improves on the JDK1.4 HashMap by adding the + * {@link org.apache.commons.collections4.MapIterator MapIterator} + * functionality and many methods for subclassing. + *

              + * Note that HashedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 3.0 + * @version $Id: HashedMap.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public class HashedMap + extends AbstractHashedMap implements Serializable, Cloneable { + + /** Serialisation version */ + private static final long serialVersionUID = -1788199231038721040L; + + /** + * Constructs a new empty map with default size and load factor. + */ + public HashedMap() { + super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD); + } + + /** + * Constructs a new, empty map with the specified initial capacity. + * + * @param initialCapacity the initial capacity + * @throws IllegalArgumentException if the initial capacity is negative + */ + public HashedMap(final int initialCapacity) { + super(initialCapacity); + } + + /** + * Constructs a new, empty map with the specified initial capacity and + * load factor. + * + * @param initialCapacity the initial capacity + * @param loadFactor the load factor + * @throws IllegalArgumentException if the initial capacity is negative + * @throws IllegalArgumentException if the load factor is less than zero + */ + public HashedMap(final int initialCapacity, final float loadFactor) { + super(initialCapacity, loadFactor); + } + + /** + * Constructor copying elements from another map. + * + * @param map the map to copy + * @throws NullPointerException if the map is null + */ + public HashedMap(final Map map) { + super(map); + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the keys or values. + * + * @return a shallow clone + */ + @Override + public HashedMap clone() { + return (HashedMap) super.clone(); + } + + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Read the map in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + +} diff --git a/src/org/apache/commons/collections4/map/LRUMap.java b/src/org/apache/commons/collections4/map/LRUMap.java new file mode 100644 index 0000000..6f384bb --- /dev/null +++ b/src/org/apache/commons/collections4/map/LRUMap.java @@ -0,0 +1,522 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.BoundedMap; + +/** + * A Map implementation with a fixed maximum size which removes + * the least recently used entry if an entry is added when full. + *

              + * The least recently used algorithm works on the get and put operations only. + * Iteration of any kind, including setting the value by iteration, does not + * change the order. Queries such as containsKey and containsValue or access + * via views also do not change the order. + *

              + * A somewhat subtle ramification of the least recently used + * algorithm is that calls to {@link #get(Object)} stand a very good chance + * of modifying the map's iteration order and thus invalidating any + * iterators currently in use. It is therefore suggested that iterations + * over an {@link LRUMap} instance access entry values only through a + * {@link org.apache.commons.collections4.MapIterator MapIterator} or {@link #entrySet()} iterator. + *

              + * The map implements OrderedMap and entries may be queried using + * the bidirectional OrderedMapIterator. The order returned is + * least recently used to most recently used. Iterators from map views can + * also be cast to OrderedIterator if required. + *

              + * All the available iterators can be reset back to the start by casting to + * ResettableIterator and calling reset(). + *

              + * Note that LRUMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * NullPointerException's when accessed by concurrent threads. + * + * @since 3.0 (previously in main package v1.0) + * @version $Id: LRUMap.java 1683016 2015-06-01 22:40:56Z tn $ + */ +public class LRUMap + extends AbstractLinkedMap implements BoundedMap, Serializable, Cloneable { + + /** Serialisation version */ + private static final long serialVersionUID = -612114643488955218L; + /** Default maximum size */ + protected static final int DEFAULT_MAX_SIZE = 100; + + /** Maximum size */ + private transient int maxSize; + /** Scan behaviour */ + private boolean scanUntilRemovable; + + /** + * Constructs a new empty map with a maximum size of 100. + */ + public LRUMap() { + this(DEFAULT_MAX_SIZE, DEFAULT_LOAD_FACTOR, false); + } + + /** + * Constructs a new, empty map with the specified maximum size. + * + * @param maxSize the maximum size of the map + * @throws IllegalArgumentException if the maximum size is less than one + */ + public LRUMap(final int maxSize) { + this(maxSize, DEFAULT_LOAD_FACTOR); + } + + /** + * Constructs a new, empty map with the specified maximum size. + * + * @param maxSize the maximum size of the map + * @param initialSize the initial size of the map + * @throws IllegalArgumentException if the maximum size is less than one + * @throws IllegalArgumentException if the initial size is negative or larger than the maximum size + * @since 4.1 + */ + public LRUMap(final int maxSize, final int initialSize) { + this(maxSize, initialSize, DEFAULT_LOAD_FACTOR); + } + + /** + * Constructs a new, empty map with the specified maximum size. + * + * @param maxSize the maximum size of the map + * @param scanUntilRemovable scan until a removeable entry is found, default false + * @throws IllegalArgumentException if the maximum size is less than one + * @since 3.1 + */ + public LRUMap(final int maxSize, final boolean scanUntilRemovable) { + this(maxSize, DEFAULT_LOAD_FACTOR, scanUntilRemovable); + } + + /** + * Constructs a new, empty map with the specified max capacity and + * load factor. + * + * @param maxSize the maximum size of the map + * @param loadFactor the load factor + * @throws IllegalArgumentException if the maximum size is less than one + * @throws IllegalArgumentException if the load factor is less than zero + */ + public LRUMap(final int maxSize, final float loadFactor) { + this(maxSize, loadFactor, false); + } + + /** + * Constructs a new, empty map with the specified max / initial capacity and + * load factor. + * + * @param maxSize the maximum size of the map + * @param initialSize the initial size of the map + * @param loadFactor the load factor + * @throws IllegalArgumentException if the maximum size is less than one + * @throws IllegalArgumentException if the initial size is negative or larger than the maximum size + * @throws IllegalArgumentException if the load factor is less than zero + * @since 4.1 + */ + public LRUMap(final int maxSize, final int initialSize, final float loadFactor) { + this(maxSize, initialSize, loadFactor, false); + } + + /** + * Constructs a new, empty map with the specified max capacity and load factor. + * + * @param maxSize the maximum size of the map + * @param loadFactor the load factor + * @param scanUntilRemovable scan until a removeable entry is found, default false + * @throws IllegalArgumentException if the maximum size is less than one + * @throws IllegalArgumentException if the load factor is less than zero + * @since 3.1 + */ + public LRUMap(final int maxSize, final float loadFactor, final boolean scanUntilRemovable) { + this(maxSize, maxSize, loadFactor, scanUntilRemovable); + } + + /** + * Constructs a new, empty map with the specified max / initial capacity and load factor. + * + * @param maxSize the maximum size of the map + * @param initialSize the initial size of the map + * @param loadFactor the load factor + * @param scanUntilRemovable scan until a removeable entry is found, default false + * @throws IllegalArgumentException if the maximum size is less than one + * @throws IllegalArgumentException if the initial size is negative or larger than the maximum size + * @throws IllegalArgumentException if the load factor is less than zero + * @since 4.1 + */ + public LRUMap(final int maxSize, + final int initialSize, + final float loadFactor, + final boolean scanUntilRemovable) { + + super(initialSize, loadFactor); + if (maxSize < 1) { + throw new IllegalArgumentException("LRUMap max size must be greater than 0"); + } + if (initialSize > maxSize) { + throw new IllegalArgumentException("LRUMap initial size must not be greather than max size"); + } + this.maxSize = maxSize; + this.scanUntilRemovable = scanUntilRemovable; + } + + /** + * Constructor copying elements from another map. + *

              + * The maximum size is set from the map's size. + * + * @param map the map to copy + * @throws NullPointerException if the map is null + * @throws IllegalArgumentException if the map is empty + */ + public LRUMap(final Map map) { + this(map, false); + } + + /** + * Constructor copying elements from another map. + *

              + * The maximum size is set from the map's size. + * + * @param map the map to copy + * @param scanUntilRemovable scan until a removeable entry is found, default false + * @throws NullPointerException if the map is null + * @throws IllegalArgumentException if the map is empty + * @since 3.1 + */ + public LRUMap(final Map map, final boolean scanUntilRemovable) { + this(map.size(), DEFAULT_LOAD_FACTOR, scanUntilRemovable); + putAll(map); + } + + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the key specified. + *

              + * This operation changes the position of the key in the map to the + * most recently used position (last). + * + * @param key the key + * @return the mapped value, null if no match + */ + @Override + public V get(final Object key) { + return get(key, true); + } + + /** + * Gets the value mapped to the key specified. + *

              + * If {@code updateToMRU} is {@code true}, the position of the key in the map + * is changed to the most recently used position (last), otherwise the iteration + * order is not changed by this operation. + * + * @param key the key + * @param updateToMRU whether the key shall be updated to the + * most recently used position + * @return the mapped value, null if no match + * @since 4.1 + */ + public V get(final Object key, final boolean updateToMRU) { + final LinkEntry entry = getEntry(key); + if (entry == null) { + return null; + } + if (updateToMRU) { + moveToMRU(entry); + } + return entry.getValue(); + } + + //----------------------------------------------------------------------- + /** + * Moves an entry to the MRU position at the end of the list. + *

              + * This implementation moves the updated entry to the end of the list. + * + * @param entry the entry to update + */ + protected void moveToMRU(final LinkEntry entry) { + if (entry.after != header) { + modCount++; + // remove + if(entry.before == null) { + throw new IllegalStateException("Entry.before is null." + + " Please check that your keys are immutable, and that you have used synchronization properly." + + " If so, then please report this to dev@commons.apache.org as a bug."); + } + entry.before.after = entry.after; + entry.after.before = entry.before; + // add first + entry.after = header; + entry.before = header.before; + header.before.after = entry; + header.before = entry; + } else if (entry == header) { + throw new IllegalStateException("Can't move header to MRU" + + " (please report this to dev@commons.apache.org)"); + } + } + + /** + * Updates an existing key-value mapping. + *

              + * This implementation moves the updated entry to the end of the list + * using {@link #moveToMRU(AbstractLinkedMap.LinkEntry)}. + * + * @param entry the entry to update + * @param newValue the new value to store + */ + @Override + protected void updateEntry(final HashEntry entry, final V newValue) { + moveToMRU((LinkEntry) entry); // handles modCount + entry.setValue(newValue); + } + + /** + * Adds a new key-value mapping into this map. + *

              + * This implementation checks the LRU size and determines whether to + * discard an entry or not using {@link #removeLRU(AbstractLinkedMap.LinkEntry)}. + *

              + * From Commons Collections 3.1 this method uses {@link #isFull()} rather + * than accessing size and maxSize directly. + * It also handles the scanUntilRemovable functionality. + * + * @param hashIndex the index into the data array to store at + * @param hashCode the hash code of the key to add + * @param key the key to add + * @param value the value to add + */ + @Override + protected void addMapping(final int hashIndex, final int hashCode, final K key, final V value) { + if (isFull()) { + LinkEntry reuse = header.after; + boolean removeLRUEntry = false; + if (scanUntilRemovable) { + while (reuse != header && reuse != null) { + if (removeLRU(reuse)) { + removeLRUEntry = true; + break; + } + reuse = reuse.after; + } + if (reuse == null) { + throw new IllegalStateException( + "Entry.after=null, header.after" + header.after + " header.before" + header.before + + " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize + + " Please check that your keys are immutable, and that you have used synchronization properly." + + " If so, then please report this to dev@commons.apache.org as a bug."); + } + } else { + removeLRUEntry = removeLRU(reuse); + } + + if (removeLRUEntry) { + if (reuse == null) { + throw new IllegalStateException( + "reuse=null, header.after=" + header.after + " header.before" + header.before + + " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize + + " Please check that your keys are immutable, and that you have used synchronization properly." + + " If so, then please report this to dev@commons.apache.org as a bug."); + } + reuseMapping(reuse, hashIndex, hashCode, key, value); + } else { + super.addMapping(hashIndex, hashCode, key, value); + } + } else { + super.addMapping(hashIndex, hashCode, key, value); + } + } + + /** + * Reuses an entry by removing it and moving it to a new place in the map. + *

              + * This method uses {@link #removeEntry}, {@link #reuseEntry} and {@link #addEntry}. + * + * @param entry the entry to reuse + * @param hashIndex the index into the data array to store at + * @param hashCode the hash code of the key to add + * @param key the key to add + * @param value the value to add + */ + protected void reuseMapping(final LinkEntry entry, final int hashIndex, final int hashCode, + final K key, final V value) { + // find the entry before the entry specified in the hash table + // remember that the parameters (except the first) refer to the new entry, + // not the old one + try { + final int removeIndex = hashIndex(entry.hashCode, data.length); + final HashEntry[] tmp = data; // may protect against some sync issues + HashEntry loop = tmp[removeIndex]; + HashEntry previous = null; + while (loop != entry && loop != null) { + previous = loop; + loop = loop.next; + } + if (loop == null) { + throw new IllegalStateException( + "Entry.next=null, data[removeIndex]=" + data[removeIndex] + " previous=" + previous + + " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize + + " Please check that your keys are immutable, and that you have used synchronization properly." + + " If so, then please report this to dev@commons.apache.org as a bug."); + } + + // reuse the entry + modCount++; + removeEntry(entry, removeIndex, previous); + reuseEntry(entry, hashIndex, hashCode, key, value); + addEntry(entry, hashIndex); + } catch (final NullPointerException ex) { + throw new IllegalStateException( + "NPE, entry=" + entry + " entryIsHeader=" + (entry==header) + + " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize + + " Please check that your keys are immutable, and that you have used synchronization properly." + + " If so, then please report this to dev@commons.apache.org as a bug."); + } + } + + /** + * Subclass method to control removal of the least recently used entry from the map. + *

              + * This method exists for subclasses to override. A subclass may wish to + * provide cleanup of resources when an entry is removed. For example: + *

              +     * protected boolean removeLRU(LinkEntry entry) {
              +     *   releaseResources(entry.getValue());  // release resources held by entry
              +     *   return true;  // actually delete entry
              +     * }
              +     * 
              + *

              + * Alternatively, a subclass may choose to not remove the entry or selectively + * keep certain LRU entries. For example: + *

              +     * protected boolean removeLRU(LinkEntry entry) {
              +     *   if (entry.getKey().toString().startsWith("System.")) {
              +     *     return false;  // entry not removed from LRUMap
              +     *   } else {
              +     *     return true;  // actually delete entry
              +     *   }
              +     * }
              +     * 
              + * The effect of returning false is dependent on the scanUntilRemovable flag. + * If the flag is true, the next LRU entry will be passed to this method and so on + * until one returns false and is removed, or every entry in the map has been passed. + * If the scanUntilRemovable flag is false, the map will exceed the maximum size. + *

              + * NOTE: Commons Collections 3.0 passed the wrong entry to this method. + * This is fixed in version 3.1 onwards. + * + * @param entry the entry to be removed + * @return {@code true} + */ + protected boolean removeLRU(final LinkEntry entry) { + return true; + } + + //----------------------------------------------------------------------- + /** + * Returns true if this map is full and no new mappings can be added. + * + * @return true if the map is full + */ + public boolean isFull() { + return size >= maxSize; + } + + /** + * Gets the maximum size of the map (the bound). + * + * @return the maximum number of elements the map can hold + */ + public int maxSize() { + return maxSize; + } + + /** + * Whether this LRUMap will scan until a removable entry is found when the + * map is full. + * + * @return true if this map scans + * @since 3.1 + */ + public boolean isScanUntilRemovable() { + return scanUntilRemovable; + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the keys or values. + * + * @return a shallow clone + */ + @Override + public LRUMap clone() { + return (LRUMap) super.clone(); + } + + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Read the map in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + + /** + * Writes the data necessary for put() to work in deserialization. + * + * @param out the output stream + * @throws IOException if an error occurs while writing to the stream + */ + @Override + protected void doWriteObject(final ObjectOutputStream out) throws IOException { + out.writeInt(maxSize); + super.doWriteObject(out); + } + + /** + * Reads the data necessary for put() to work in the superclass. + * + * @param in the input stream + * @throws IOException if an error occurs while reading from the stream + * @throws ClassNotFoundException if an object read from the stream can not be loaded + */ + @Override + protected void doReadObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + maxSize = in.readInt(); + super.doReadObject(in); + } + +} diff --git a/src/org/apache/commons/collections4/map/LazyMap.java b/src/org/apache/commons/collections4/map/LazyMap.java new file mode 100644 index 0000000..39ac202 --- /dev/null +++ b/src/org/apache/commons/collections4/map/LazyMap.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.functors.FactoryTransformer; + +/** + * Decorates another Map to create objects in the map on demand. + *

              + * When the {@link #get(Object)} method is called with a key that does not + * exist in the map, the factory is used to create the object. The created + * object will be added to the map using the requested key. + *

              + * For instance: + *

              + * Factory<Date> factory = new Factory<Date>() {
              + *     public Date create() {
              + *         return new Date();
              + *     }
              + * }
              + * Map<String, Date> lazy = LazyMap.lazyMap(new HashMap<String, Date>(), factory);
              + * Date date = lazy.get("NOW");
              + * 
              + * + * After the above code is executed, date will refer to + * a new Date instance. Furthermore, that Date + * instance is mapped to the "NOW" key in the map. + *

              + * Note that LazyMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: LazyMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class LazyMap extends AbstractMapDecorator implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 7990956402564206740L; + + /** The factory to use to construct elements */ + protected final Transformer factory; + + /** + * Factory method to create a lazily instantiated map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @return a new lazy map + * @throws NullPointerException if map or factory is null + * @since 4.0 + */ + public static LazyMap lazyMap(final Map map, final Factory< ? extends V> factory) { + return new LazyMap(map, factory); + } + + /** + * Factory method to create a lazily instantiated map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @return a new lazy map + * @throws NullPointerException if map or factory is null + * @since 4.0 + */ + public static LazyMap lazyMap(final Map map, final Transformer factory) { + return new LazyMap(map, factory); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @throws NullPointerException if map or factory is null + */ + protected LazyMap(final Map map, final Factory factory) { + super(map); + if (factory == null) { + throw new NullPointerException("Factory must not be null"); + } + this.factory = FactoryTransformer.factoryTransformer(factory); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @throws NullPointerException if map or factory is null + */ + protected LazyMap(final Map map, final Transformer factory) { + super(map); + if (factory == null) { + throw new NullPointerException("Factory must not be null"); + } + this.factory = factory; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); + } + + //----------------------------------------------------------------------- + @Override + public V get(final Object key) { + // create value for key if key is not currently in the map + if (map.containsKey(key) == false) { + @SuppressWarnings("unchecked") + final K castKey = (K) key; + final V value = factory.transform(castKey); + map.put(castKey, value); + return value; + } + return map.get(key); + } + + // no need to wrap keySet, entrySet or values as they are views of + // existing map entries - you can't do a map-style get on them. +} diff --git a/src/org/apache/commons/collections4/map/LazySortedMap.java b/src/org/apache/commons/collections4/map/LazySortedMap.java new file mode 100644 index 0000000..9d265e6 --- /dev/null +++ b/src/org/apache/commons/collections4/map/LazySortedMap.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.Comparator; +import java.util.SortedMap; + +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another SortedMap to create objects in the map on demand. + *

              + * When the {@link #get(Object)} method is called with a key that does not + * exist in the map, the factory is used to create the object. The created + * object will be added to the map using the requested key. + *

              + * For instance: + *

              + * Factory<Date> factory = new Factory<Date>() {
              + *     public Date create() {
              + *         return new Date();
              + *     }
              + * }
              + * SortedMap<String, Date> lazy =
              + *     LazySortedMap.lazySortedMap(new HashMap<String, Date>(), factory);
              + * Date date = lazy.get("NOW");
              + * 
              + * + * After the above code is executed, date will refer to + * a new Date instance. Furthermore, that Date + * instance is mapped to the "NOW" key in the map. + *

              + * Note that LazySortedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedSortedMap}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: LazySortedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class LazySortedMap extends LazyMap implements SortedMap { + + /** Serialization version */ + private static final long serialVersionUID = 2715322183617658933L; + + /** + * Factory method to create a lazily instantiated sorted map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @return a new lazy sorted map + * @throws NullPointerException if map or factory is null + * @since 4.0 + */ + public static LazySortedMap lazySortedMap(final SortedMap map, + final Factory factory) { + return new LazySortedMap(map, factory); + } + + /** + * Factory method to create a lazily instantiated sorted map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @return a new lazy sorted map + * @throws NullPointerException if map or factory is null + * @since 4.0 + */ + public static LazySortedMap lazySortedMap(final SortedMap map, + final Transformer factory) { + return new LazySortedMap(map, factory); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @throws NullPointerException if map or factory is null + */ + protected LazySortedMap(final SortedMap map, final Factory factory) { + super(map, factory); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param factory the factory to use, must not be null + * @throws NullPointerException if map or factory is null + */ + protected LazySortedMap(final SortedMap map, final Transformer factory) { + super(map, factory); + } + + //----------------------------------------------------------------------- + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + protected SortedMap getSortedMap() { + return (SortedMap) map; + } + + //----------------------------------------------------------------------- + public K firstKey() { + return getSortedMap().firstKey(); + } + + public K lastKey() { + return getSortedMap().lastKey(); + } + + public Comparator comparator() { + return getSortedMap().comparator(); + } + + public SortedMap subMap(final K fromKey, final K toKey) { + final SortedMap map = getSortedMap().subMap(fromKey, toKey); + return new LazySortedMap(map, factory); + } + + public SortedMap headMap(final K toKey) { + final SortedMap map = getSortedMap().headMap(toKey); + return new LazySortedMap(map, factory); + } + + public SortedMap tailMap(final K fromKey) { + final SortedMap map = getSortedMap().tailMap(fromKey); + return new LazySortedMap(map, factory); + } + +} diff --git a/src/org/apache/commons/collections4/map/LinkedMap.java b/src/org/apache/commons/collections4/map/LinkedMap.java new file mode 100644 index 0000000..924bb40 --- /dev/null +++ b/src/org/apache/commons/collections4/map/LinkedMap.java @@ -0,0 +1,303 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.AbstractList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import org.apache.commons.collections4.iterators.UnmodifiableIterator; +import org.apache.commons.collections4.iterators.UnmodifiableListIterator; +import org.apache.commons.collections4.list.UnmodifiableList; + +/** + * A Map implementation that maintains the order of the entries. + * In this implementation order is maintained by original insertion. + *

              + * This implementation improves on the JDK1.4 LinkedHashMap by adding the + * {@link org.apache.commons.collections4.MapIterator MapIterator} + * functionality, additional convenience methods and allowing + * bidirectional iteration. It also implements OrderedMap. + * In addition, non-interface methods are provided to access the map by index. + *

              + * The orderedMapIterator() method provides direct access to a + * bidirectional iterator. The iterators from the other views can also be cast + * to OrderedIterator if required. + *

              + * All the available iterators can be reset back to the start by casting to + * ResettableIterator and calling reset(). + *

              + * The implementation is also designed to be subclassed, with lots of useful + * methods exposed. + *

              + * Note that LinkedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 3.0 + * @version $Id: LinkedMap.java 1533984 2013-10-20 21:12:51Z tn $ + */ +public class LinkedMap extends AbstractLinkedMap implements Serializable, Cloneable { + + /** Serialisation version */ + private static final long serialVersionUID = 9077234323521161066L; + + /** + * Constructs a new empty map with default size and load factor. + */ + public LinkedMap() { + super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD); + } + + /** + * Constructs a new, empty map with the specified initial capacity. + * + * @param initialCapacity the initial capacity + * @throws IllegalArgumentException if the initial capacity is negative + */ + public LinkedMap(final int initialCapacity) { + super(initialCapacity); + } + + /** + * Constructs a new, empty map with the specified initial capacity and + * load factor. + * + * @param initialCapacity the initial capacity + * @param loadFactor the load factor + * @throws IllegalArgumentException if the initial capacity is negative + * @throws IllegalArgumentException if the load factor is less than zero + */ + public LinkedMap(final int initialCapacity, final float loadFactor) { + super(initialCapacity, loadFactor); + } + + /** + * Constructor copying elements from another map. + * + * @param map the map to copy + * @throws NullPointerException if the map is null + */ + public LinkedMap(final Map map) { + super(map); + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the keys or values. + * + * @return a shallow clone + */ + @Override + public LinkedMap clone() { + return (LinkedMap) super.clone(); + } + + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Read the map in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + + //----------------------------------------------------------------------- + /** + * Gets the key at the specified index. + * + * @param index the index to retrieve + * @return the key at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public K get(final int index) { + return getEntry(index).getKey(); + } + + /** + * Gets the value at the specified index. + * + * @param index the index to retrieve + * @return the value at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public V getValue(final int index) { + return getEntry(index).getValue(); + } + + /** + * Gets the index of the specified key. + * + * @param key the key to find the index of + * @return the index, or -1 if not found + */ + public int indexOf(Object key) { + key = convertKey(key); + int i = 0; + for (LinkEntry entry = header.after; entry != header; entry = entry.after, i++) { + if (isEqualKey(key, entry.key)) { + return i; + } + } + return -1; + } + + /** + * Removes the element at the specified index. + * + * @param index the index of the object to remove + * @return the previous value corresponding the key, + * or null if none existed + * @throws IndexOutOfBoundsException if the index is invalid + */ + public V remove(final int index) { + return remove(get(index)); + } + + /** + * Gets an unmodifiable List view of the keys. + *

              + * The returned list is unmodifiable because changes to the values of + * the list (using {@link java.util.ListIterator#set(Object)}) will + * effectively remove the value from the list and reinsert that value at + * the end of the list, which is an unexpected side effect of changing the + * value of a list. This occurs because changing the key, changes when the + * mapping is added to the map and thus where it appears in the list. + *

              + * An alternative to this method is to use {@link #keySet()}. + * + * @see #keySet() + * @return The ordered list of keys. + */ + public List asList() { + return new LinkedMapList(this); + } + + /** + * List view of map. + */ + static class LinkedMapList extends AbstractList { + + private final LinkedMap parent; + + LinkedMapList(final LinkedMap parent) { + this.parent = parent; + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public K get(final int index) { + return parent.get(index); + } + + @Override + public boolean contains(final Object obj) { + return parent.containsKey(obj); + } + + @Override + public int indexOf(final Object obj) { + return parent.indexOf(obj); + } + + @Override + public int lastIndexOf(final Object obj) { + return parent.indexOf(obj); + } + + @Override + public boolean containsAll(final Collection coll) { + return parent.keySet().containsAll(coll); + } + + @Override + public K remove(final int index) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object obj) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Object[] toArray() { + return parent.keySet().toArray(); + } + + @Override + public T[] toArray(final T[] array) { + return parent.keySet().toArray(array); + } + + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(parent.keySet().iterator()); + } + + @Override + public ListIterator listIterator() { + return UnmodifiableListIterator.umodifiableListIterator(super.listIterator()); + } + + @Override + public ListIterator listIterator(final int fromIndex) { + return UnmodifiableListIterator.umodifiableListIterator(super.listIterator(fromIndex)); + } + + @Override + public List subList(final int fromIndexInclusive, final int toIndexExclusive) { + return UnmodifiableList.unmodifiableList(super.subList(fromIndexInclusive, toIndexExclusive)); + } + } + +} diff --git a/src/org/apache/commons/collections4/map/ListOrderedMap.java b/src/org/apache/commons/collections4/map/ListOrderedMap.java new file mode 100644 index 0000000..df4aefc --- /dev/null +++ b/src/org/apache/commons/collections4/map/ListOrderedMap.java @@ -0,0 +1,786 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.AbstractList; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.ResettableIterator; +import org.apache.commons.collections4.iterators.AbstractUntypedIteratorDecorator; +import org.apache.commons.collections4.keyvalue.AbstractMapEntry; +import org.apache.commons.collections4.list.UnmodifiableList; + +/** + * Decorates a Map to ensure that the order of addition is retained + * using a List to maintain order. + *

              + * The order will be used via the iterators and toArray methods on the views. + * The order is also returned by the MapIterator. + * The orderedMapIterator() method accesses an iterator that can + * iterate both forwards and backwards through the map. + * In addition, non-interface methods are provided to access the map by index. + *

              + * If an object is added to the Map for a second time, it will remain in the + * original position in the iteration. + *

              + * Note that ListOrderedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * Note that ListOrderedMap doesn't work with + * {@link java.util.IdentityHashMap IdentityHashMap}, {@link CaseInsensitiveMap}, + * or similar maps that violate the general contract of {@link java.util.Map}. + * The ListOrderedMap (or, more precisely, the underlying List) + * is relying on {@link Object#equals(Object) equals()}. This is fine, as long as the + * decorated Map is also based on {@link Object#equals(Object) equals()}, + * and {@link Object#hashCode() hashCode()}, which + * {@link java.util.IdentityHashMap IdentityHashMap}, and + * {@link CaseInsensitiveMap} don't: The former uses ==, and + * the latter uses {@link Object#equals(Object) equals()} on a lower-cased + * key. + *

              + * This class is {@link Serializable} starting with Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: ListOrderedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ListOrderedMap + extends AbstractMapDecorator + implements OrderedMap, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 2728177751851003750L; + + /** Internal list to hold the sequence of objects */ + private final List insertOrder = new ArrayList(); + + /** + * Factory method to create an ordered map. + *

              + * An ArrayList is used to retain order. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return a new list ordered map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static ListOrderedMap listOrderedMap(final Map map) { + return new ListOrderedMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructs a new empty ListOrderedMap that decorates + * a HashMap. + * + * @since 3.1 + */ + public ListOrderedMap() { + this(new HashMap()); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + protected ListOrderedMap(final Map map) { + super(map); + insertOrder.addAll(decorated().keySet()); + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + // Implement OrderedMap + //----------------------------------------------------------------------- + @Override + public OrderedMapIterator mapIterator() { + return new ListOrderedMapIterator(this); + } + + /** + * Gets the first key in this map by insert order. + * + * @return the first key currently in this map + * @throws NoSuchElementException if this map is empty + */ + public K firstKey() { + if (size() == 0) { + throw new NoSuchElementException("Map is empty"); + } + return insertOrder.get(0); + } + + /** + * Gets the last key in this map by insert order. + * + * @return the last key currently in this map + * @throws NoSuchElementException if this map is empty + */ + public K lastKey() { + if (size() == 0) { + throw new NoSuchElementException("Map is empty"); + } + return insertOrder.get(size() - 1); + } + + /** + * Gets the next key to the one specified using insert order. + * This method performs a list search to find the key and is O(n). + * + * @param key the key to find previous for + * @return the next key, null if no match or at start + */ + public K nextKey(final Object key) { + final int index = insertOrder.indexOf(key); + if (index >= 0 && index < size() - 1) { + return insertOrder.get(index + 1); + } + return null; + } + + /** + * Gets the previous key to the one specified using insert order. + * This method performs a list search to find the key and is O(n). + * + * @param key the key to find previous for + * @return the previous key, null if no match or at start + */ + public K previousKey(final Object key) { + final int index = insertOrder.indexOf(key); + if (index > 0) { + return insertOrder.get(index - 1); + } + return null; + } + + //----------------------------------------------------------------------- + @Override + public V put(final K key, final V value) { + if (decorated().containsKey(key)) { + // re-adding doesn't change order + return decorated().put(key, value); + } + // first add, so add to both map and list + final V result = decorated().put(key, value); + insertOrder.add(key); + return result; + } + + @Override + public void putAll(final Map map) { + for (final Map.Entry entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + /** + * Puts the values contained in a supplied Map into the Map starting at + * the specified index. + * + * @param index the index in the Map to start at. + * @param map the Map containing the entries to be added. + * @throws IndexOutOfBoundsException if the index is out of range [0, size] + */ + public void putAll(int index, final Map map) { + if (index < 0 || index > insertOrder.size()) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + insertOrder.size()); + } + for (final Map.Entry entry : map.entrySet()) { + final K key = entry.getKey(); + final boolean contains = containsKey(key); + // The return value of put is null if the key did not exist OR the value was null + // so it cannot be used to determine whether the key was added + put(index, entry.getKey(), entry.getValue()); + if (!contains) { + // if no key was replaced, increment the index + index++; + } else { + // otherwise put the next item after the currently inserted key + index = indexOf(entry.getKey()) + 1; + } + } + } + + @Override + public V remove(final Object key) { + V result = null; + if (decorated().containsKey(key)) { + result = decorated().remove(key); + insertOrder.remove(key); + } + return result; + } + + @Override + public void clear() { + decorated().clear(); + insertOrder.clear(); + } + + //----------------------------------------------------------------------- + /** + * Gets a view over the keys in the map. + *

              + * The Collection will be ordered by object insertion into the map. + * + * @see #keyList() + * @return the fully modifiable collection view over the keys + */ + @Override + public Set keySet() { + return new KeySetView(this); + } + + /** + * Gets a view over the keys in the map as a List. + *

              + * The List will be ordered by object insertion into the map. + * The List is unmodifiable. + * + * @see #keySet() + * @return the unmodifiable list view over the keys + * @since 3.2 + */ + public List keyList() { + return UnmodifiableList.unmodifiableList(insertOrder); + } + + /** + * Gets a view over the values in the map. + *

              + * The Collection will be ordered by object insertion into the map. + *

              + * From Commons Collections 3.2, this Collection can be cast + * to a list, see {@link #valueList()} + * + * @see #valueList() + * @return the fully modifiable collection view over the values + */ + @Override + public Collection values() { + return new ValuesView(this); + } + + /** + * Gets a view over the values in the map as a List. + *

              + * The List will be ordered by object insertion into the map. + * The List supports remove and set, but does not support add. + * + * @see #values() + * @return the partially modifiable list view over the values + * @since 3.2 + */ + public List valueList() { + return new ValuesView(this); + } + + /** + * Gets a view over the entries in the map. + *

              + * The Set will be ordered by object insertion into the map. + * + * @return the fully modifiable set view over the entries + */ + @Override + public Set> entrySet() { + return new EntrySetView(this, this.insertOrder); + } + + //----------------------------------------------------------------------- + /** + * Returns the Map as a string. + * + * @return the Map as a String + */ + @Override + public String toString() { + if (isEmpty()) { + return "{}"; + } + final StringBuilder buf = new StringBuilder(); + buf.append('{'); + boolean first = true; + for (final Map.Entry entry : entrySet()) { + final K key = entry.getKey(); + final V value = entry.getValue(); + if (first) { + first = false; + } else { + buf.append(", "); + } + buf.append(key == this ? "(this Map)" : key); + buf.append('='); + buf.append(value == this ? "(this Map)" : value); + } + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * Gets the key at the specified index. + * + * @param index the index to retrieve + * @return the key at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public K get(final int index) { + return insertOrder.get(index); + } + + /** + * Gets the value at the specified index. + * + * @param index the index to retrieve + * @return the key at the specified index + * @throws IndexOutOfBoundsException if the index is invalid + */ + public V getValue(final int index) { + return get(insertOrder.get(index)); + } + + /** + * Gets the index of the specified key. + * + * @param key the key to find the index of + * @return the index, or -1 if not found + */ + public int indexOf(final Object key) { + return insertOrder.indexOf(key); + } + + /** + * Sets the value at the specified index. + * + * @param index the index of the value to set + * @param value the new value to set + * @return the previous value at that index + * @throws IndexOutOfBoundsException if the index is invalid + * @since 3.2 + */ + public V setValue(final int index, final V value) { + final K key = insertOrder.get(index); + return put(key, value); + } + + /** + * Puts a key-value mapping into the map at the specified index. + *

              + * If the map already contains the key, then the original mapping + * is removed and the new mapping added at the specified index. + * The remove may change the effect of the index. The index is + * always calculated relative to the original state of the map. + *

              + * Thus the steps are: (1) remove the existing key-value mapping, + * then (2) insert the new key-value mapping at the position it + * would have been inserted had the remove not occurred. + * + * @param index the index at which the mapping should be inserted + * @param key the key + * @param value the value + * @return the value previously mapped to the key + * @throws IndexOutOfBoundsException if the index is out of range [0, size] + * @since 3.2 + */ + public V put(int index, final K key, final V value) { + if (index < 0 || index > insertOrder.size()) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + insertOrder.size()); + } + + final Map m = decorated(); + if (m.containsKey(key)) { + final V result = m.remove(key); + final int pos = insertOrder.indexOf(key); + insertOrder.remove(pos); + if (pos < index) { + index--; + } + insertOrder.add(index, key); + m.put(key, value); + return result; + } + insertOrder.add(index, key); + m.put(key, value); + return null; + } + + /** + * Removes the element at the specified index. + * + * @param index the index of the object to remove + * @return the removed value, or null if none existed + * @throws IndexOutOfBoundsException if the index is invalid + */ + public V remove(final int index) { + return remove(get(index)); + } + + /** + * Gets an unmodifiable List view of the keys which changes as the map changes. + *

              + * The returned list is unmodifiable because changes to the values of + * the list (using {@link java.util.ListIterator#set(Object)}) will + * effectively remove the value from the list and reinsert that value at + * the end of the list, which is an unexpected side effect of changing the + * value of a list. This occurs because changing the key, changes when the + * mapping is added to the map and thus where it appears in the list. + *

              + * An alternative to this method is to use the better named + * {@link #keyList()} or {@link #keySet()}. + * + * @see #keyList() + * @see #keySet() + * @return The ordered list of keys. + */ + public List asList() { + return keyList(); + } + + //----------------------------------------------------------------------- + static class ValuesView extends AbstractList { + private final ListOrderedMap parent; + + @SuppressWarnings("unchecked") + ValuesView(final ListOrderedMap parent) { + super(); + this.parent = (ListOrderedMap) parent; + } + + @Override + public int size() { + return this.parent.size(); + } + + @Override + public boolean contains(final Object value) { + return this.parent.containsValue(value); + } + + @Override + public void clear() { + this.parent.clear(); + } + + @Override + public Iterator iterator() { + return new AbstractUntypedIteratorDecorator, V>(parent.entrySet().iterator()) { + public V next() { + return getIterator().next().getValue(); + } + }; + } + + @Override + public V get(final int index) { + return this.parent.getValue(index); + } + + @Override + public V set(final int index, final V value) { + return this.parent.setValue(index, value); + } + + @Override + public V remove(final int index) { + return this.parent.remove(index); + } + } + + //----------------------------------------------------------------------- + static class KeySetView extends AbstractSet { + private final ListOrderedMap parent; + + @SuppressWarnings("unchecked") + KeySetView(final ListOrderedMap parent) { + super(); + this.parent = (ListOrderedMap) parent; + } + + @Override + public int size() { + return this.parent.size(); + } + + @Override + public boolean contains(final Object value) { + return this.parent.containsKey(value); + } + + @Override + public void clear() { + this.parent.clear(); + } + + @Override + public Iterator iterator() { + return new AbstractUntypedIteratorDecorator, K>(parent.entrySet().iterator()) { + public K next() { + return getIterator().next().getKey(); + } + }; + } + } + + //----------------------------------------------------------------------- + static class EntrySetView extends AbstractSet> { + private final ListOrderedMap parent; + private final List insertOrder; + private Set> entrySet; + + public EntrySetView(final ListOrderedMap parent, final List insertOrder) { + super(); + this.parent = parent; + this.insertOrder = insertOrder; + } + + private Set> getEntrySet() { + if (entrySet == null) { + entrySet = parent.decorated().entrySet(); + } + return entrySet; + } + + @Override + public int size() { + return this.parent.size(); + } + @Override + public boolean isEmpty() { + return this.parent.isEmpty(); + } + + @Override + public boolean contains(final Object obj) { + return getEntrySet().contains(obj); + } + + @Override + public boolean containsAll(final Collection coll) { + return getEntrySet().containsAll(coll); + } + + @Override + @SuppressWarnings("unchecked") + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + if (getEntrySet().contains(obj)) { + final Object key = ((Map.Entry) obj).getKey(); + parent.remove(key); + return true; + } + return false; + } + + @Override + public void clear() { + this.parent.clear(); + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + return getEntrySet().equals(obj); + } + + @Override + public int hashCode() { + return getEntrySet().hashCode(); + } + + @Override + public String toString() { + return getEntrySet().toString(); + } + + @Override + public Iterator> iterator() { + return new ListOrderedIterator(parent, insertOrder); + } + } + + //----------------------------------------------------------------------- + static class ListOrderedIterator extends AbstractUntypedIteratorDecorator> { + private final ListOrderedMap parent; + private K last = null; + + ListOrderedIterator(final ListOrderedMap parent, final List insertOrder) { + super(insertOrder.iterator()); + this.parent = parent; + } + + public Map.Entry next() { + last = getIterator().next(); + return new ListOrderedMapEntry(parent, last); + } + + @Override + public void remove() { + super.remove(); + parent.decorated().remove(last); + } + } + + //----------------------------------------------------------------------- + static class ListOrderedMapEntry extends AbstractMapEntry { + private final ListOrderedMap parent; + + ListOrderedMapEntry(final ListOrderedMap parent, final K key) { + super(key, null); + this.parent = parent; + } + + @Override + public V getValue() { + return parent.get(getKey()); + } + + @Override + public V setValue(final V value) { + return parent.decorated().put(getKey(), value); + } + } + + //----------------------------------------------------------------------- + static class ListOrderedMapIterator implements OrderedMapIterator, ResettableIterator { + private final ListOrderedMap parent; + private ListIterator iterator; + private K last = null; + private boolean readable = false; + + ListOrderedMapIterator(final ListOrderedMap parent) { + super(); + this.parent = parent; + this.iterator = parent.insertOrder.listIterator(); + } + + public boolean hasNext() { + return iterator.hasNext(); + } + + public K next() { + last = iterator.next(); + readable = true; + return last; + } + + public boolean hasPrevious() { + return iterator.hasPrevious(); + } + + public K previous() { + last = iterator.previous(); + readable = true; + return last; + } + + public void remove() { + if (readable == false) { + throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID); + } + iterator.remove(); + parent.map.remove(last); + readable = false; + } + + public K getKey() { + if (readable == false) { + throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID); + } + return last; + } + + public V getValue() { + if (readable == false) { + throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID); + } + return parent.get(last); + } + + public V setValue(final V value) { + if (readable == false) { + throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID); + } + return parent.map.put(last, value); + } + + public void reset() { + iterator = parent.insertOrder.listIterator(); + last = null; + readable = false; + } + + @Override + public String toString() { + if (readable == true) { + return "Iterator[" + getKey() + "=" + getValue() + "]"; + } + return "Iterator[]"; + } + } + +} diff --git a/src/org/apache/commons/collections4/map/MultiKeyMap.java b/src/org/apache/commons/collections4/map/MultiKeyMap.java new file mode 100644 index 0000000..849f293 --- /dev/null +++ b/src/org/apache/commons/collections4/map/MultiKeyMap.java @@ -0,0 +1,908 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.keyvalue.MultiKey; + +/** + * A Map implementation that uses multiple keys to map the value. + *

              + * This class is the most efficient way to uses multiple keys to map to a value. + * The best way to use this class is via the additional map-style methods. + * These provide get, containsKey, put and + * remove for individual keys which operate without extra object creation. + *

              + * The additional methods are the main interface of this map. + * As such, you will not normally hold this map in a variable of type Map. + *

              + * The normal map methods take in and return a {@link MultiKey}. + * If you try to use put() with any other object type a + * ClassCastException is thrown. If you try to use null as + * the key in put() a NullPointerException is thrown. + *

              + * This map is implemented as a decorator of a AbstractHashedMap which + * enables extra behaviour to be added easily. + *

                + *
              • MultiKeyMap.decorate(new LinkedMap()) creates an ordered map. + *
              • MultiKeyMap.decorate(new LRUMap()) creates an least recently used map. + *
              • MultiKeyMap.decorate(new ReferenceMap()) creates a garbage collector sensitive map. + *
              + * Note that IdentityMap and ReferenceIdentityMap are unsuitable + * for use as the key comparison would work on the whole MultiKey, not the elements within. + *

              + * As an example, consider a least recently used cache that uses a String airline code + * and a Locale to lookup the airline's name: + *

              + * private MultiKeyMap cache = MultiKeyMap.multiKeyMap(new LRUMap(50));
              + *
              + * public String getAirlineName(String code, String locale) {
              + *   String name = (String) cache.get(code, locale);
              + *   if (name == null) {
              + *     name = getAirlineNameFromDB(code, locale);
              + *     cache.put(code, locale, name);
              + *   }
              + *   return name;
              + * }
              + * 
              + *

              + * Note that MultiKeyMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. This class may throw exceptions when accessed + * by concurrent threads without synchronization. + * + * @since 3.1 + * @version $Id: MultiKeyMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class MultiKeyMap extends AbstractMapDecorator, V> + implements Serializable, Cloneable { + + /** Serialisation version */ + private static final long serialVersionUID = -1788199231038721040L; + + //----------------------------------------------------------------------- + /** + * Decorates the specified map to add the MultiKeyMap API and fast query. + * The map must not be null and must be empty. + * + * @param the key type + * @param the value type + * @param map the map to decorate, not null + * @return a new multi key map + * @throws NullPointerException if map is null + * @throws IllegalArgumentException if the map is not empty + * @since 4.0 + */ + public static MultiKeyMap multiKeyMap(final AbstractHashedMap, V> map) { + if (map == null) { + throw new NullPointerException("Map must not be null"); + } + if (map.size() > 0) { + throw new IllegalArgumentException("Map must be empty"); + } + return new MultiKeyMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructs a new MultiKeyMap that decorates a HashedMap. + */ + public MultiKeyMap() { + this(new HashedMap, V>()); + } + + /** + * Constructor that decorates the specified map and is called from + * {@link #multiKeyMap(AbstractHashedMap)}. + * The map must not be null and should be empty or only contain valid keys. + * This constructor performs no validation. + * + * @param map the map to decorate + */ + protected MultiKeyMap(final AbstractHashedMap, V> map) { + super(map); + this.map = map; + } + + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @return the mapped value, null if no match + */ + public V get(final Object key1, final Object key2) { + final int hashCode = hash(key1, key2); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) { + return entry.getValue(); + } + entry = entry.next; + } + return null; + } + + /** + * Checks whether the map contains the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @return true if the map contains the key + */ + public boolean containsKey(final Object key1, final Object key2) { + final int hashCode = hash(key1, key2); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) { + return true; + } + entry = entry.next; + } + return false; + } + + /** + * Stores the value against the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param value the value to store + * @return the value previously mapped to this combined key, null if none + */ + public V put(final K key1, final K key2, final V value) { + final int hashCode = hash(key1, key2); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) { + final V oldValue = entry.getValue(); + decorated().updateEntry(entry, value); + return oldValue; + } + entry = entry.next; + } + decorated().addMapping(index, hashCode, new MultiKey(key1, key2), value); + return null; + } + + /** + * Removes the specified multi-key from this map. + * + * @param key1 the first key + * @param key2 the second key + * @return the value mapped to the removed key, null if key not in map + * @since 4.0 (previous name: remove(Object, Object)) + */ + public V removeMultiKey(final Object key1, final Object key2) { + final int hashCode = hash(key1, key2); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + AbstractHashedMap.HashEntry, V> previous = null; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) { + final V oldValue = entry.getValue(); + decorated().removeMapping(entry, index, previous); + return oldValue; + } + previous = entry; + entry = entry.next; + } + return null; + } + + /** + * Gets the hash code for the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @return the hash code + */ + protected int hash(final Object key1, final Object key2) { + int h = 0; + if (key1 != null) { + h ^= key1.hashCode(); + } + if (key2 != null) { + h ^= key2.hashCode(); + } + h += ~(h << 9); + h ^= h >>> 14; + h += h << 4; + h ^= h >>> 10; + return h; + } + + /** + * Is the key equal to the combined key. + * + * @param entry the entry to compare to + * @param key1 the first key + * @param key2 the second key + * @return true if the key matches + */ + protected boolean isEqualKey(final AbstractHashedMap.HashEntry, V> entry, + final Object key1, final Object key2) { + final MultiKey multi = entry.getKey(); + return + multi.size() == 2 && + (key1 == multi.getKey(0) || key1 != null && key1.equals(multi.getKey(0))) && + (key2 == multi.getKey(1) || key2 != null && key2.equals(multi.getKey(1))); + } + + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @return the mapped value, null if no match + */ + public V get(final Object key1, final Object key2, final Object key3) { + final int hashCode = hash(key1, key2, key3); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) { + return entry.getValue(); + } + entry = entry.next; + } + return null; + } + + /** + * Checks whether the map contains the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @return true if the map contains the key + */ + public boolean containsKey(final Object key1, final Object key2, final Object key3) { + final int hashCode = hash(key1, key2, key3); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) { + return true; + } + entry = entry.next; + } + return false; + } + + /** + * Stores the value against the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param value the value to store + * @return the value previously mapped to this combined key, null if none + */ + public V put(final K key1, final K key2, final K key3, final V value) { + final int hashCode = hash(key1, key2, key3); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) { + final V oldValue = entry.getValue(); + decorated().updateEntry(entry, value); + return oldValue; + } + entry = entry.next; + } + decorated().addMapping(index, hashCode, new MultiKey(key1, key2, key3), value); + return null; + } + + /** + * Removes the specified multi-key from this map. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @return the value mapped to the removed key, null if key not in map + * @since 4.0 (previous name: remove(Object, Object, Object)) + */ + public V removeMultiKey(final Object key1, final Object key2, final Object key3) { + final int hashCode = hash(key1, key2, key3); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + AbstractHashedMap.HashEntry, V> previous = null; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) { + final V oldValue = entry.getValue(); + decorated().removeMapping(entry, index, previous); + return oldValue; + } + previous = entry; + entry = entry.next; + } + return null; + } + + /** + * Gets the hash code for the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @return the hash code + */ + protected int hash(final Object key1, final Object key2, final Object key3) { + int h = 0; + if (key1 != null) { + h ^= key1.hashCode(); + } + if (key2 != null) { + h ^= key2.hashCode(); + } + if (key3 != null) { + h ^= key3.hashCode(); + } + h += ~(h << 9); + h ^= h >>> 14; + h += h << 4; + h ^= h >>> 10; + return h; + } + + /** + * Is the key equal to the combined key. + * + * @param entry the entry to compare to + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @return true if the key matches + */ + protected boolean isEqualKey(final AbstractHashedMap.HashEntry, V> entry, + final Object key1, final Object key2, final Object key3) { + final MultiKey multi = entry.getKey(); + return + multi.size() == 3 && + (key1 == multi.getKey(0) || key1 != null && key1.equals(multi.getKey(0))) && + (key2 == multi.getKey(1) || key2 != null && key2.equals(multi.getKey(1))) && + (key3 == multi.getKey(2) || key3 != null && key3.equals(multi.getKey(2))); + } + + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @return the mapped value, null if no match + */ + public V get(final Object key1, final Object key2, final Object key3, final Object key4) { + final int hashCode = hash(key1, key2, key3, key4); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) { + return entry.getValue(); + } + entry = entry.next; + } + return null; + } + + /** + * Checks whether the map contains the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @return true if the map contains the key + */ + public boolean containsKey(final Object key1, final Object key2, final Object key3, final Object key4) { + final int hashCode = hash(key1, key2, key3, key4); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) { + return true; + } + entry = entry.next; + } + return false; + } + + /** + * Stores the value against the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param value the value to store + * @return the value previously mapped to this combined key, null if none + */ + public V put(final K key1, final K key2, final K key3, final K key4, final V value) { + final int hashCode = hash(key1, key2, key3, key4); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) { + final V oldValue = entry.getValue(); + decorated().updateEntry(entry, value); + return oldValue; + } + entry = entry.next; + } + decorated().addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4), value); + return null; + } + + /** + * Removes the specified multi-key from this map. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @return the value mapped to the removed key, null if key not in map + * @since 4.0 (previous name: remove(Object, Object, Object, Object)) + */ + public V removeMultiKey(final Object key1, final Object key2, final Object key3, final Object key4) { + final int hashCode = hash(key1, key2, key3, key4); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + AbstractHashedMap.HashEntry, V> previous = null; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) { + final V oldValue = entry.getValue(); + decorated().removeMapping(entry, index, previous); + return oldValue; + } + previous = entry; + entry = entry.next; + } + return null; + } + + /** + * Gets the hash code for the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @return the hash code + */ + protected int hash(final Object key1, final Object key2, final Object key3, final Object key4) { + int h = 0; + if (key1 != null) { + h ^= key1.hashCode(); + } + if (key2 != null) { + h ^= key2.hashCode(); + } + if (key3 != null) { + h ^= key3.hashCode(); + } + if (key4 != null) { + h ^= key4.hashCode(); + } + h += ~(h << 9); + h ^= h >>> 14; + h += h << 4; + h ^= h >>> 10; + return h; + } + + /** + * Is the key equal to the combined key. + * + * @param entry the entry to compare to + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @return true if the key matches + */ + protected boolean isEqualKey(final AbstractHashedMap.HashEntry, V> entry, + final Object key1, final Object key2, final Object key3, final Object key4) { + final MultiKey multi = entry.getKey(); + return + multi.size() == 4 && + (key1 == multi.getKey(0) || key1 != null && key1.equals(multi.getKey(0))) && + (key2 == multi.getKey(1) || key2 != null && key2.equals(multi.getKey(1))) && + (key3 == multi.getKey(2) || key3 != null && key3.equals(multi.getKey(2))) && + (key4 == multi.getKey(3) || key4 != null && key4.equals(multi.getKey(3))); + } + + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param key5 the fifth key + * @return the mapped value, null if no match + */ + public V get(final Object key1, final Object key2, final Object key3, final Object key4, final Object key5) { + final int hashCode = hash(key1, key2, key3, key4, key5); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) { + return entry.getValue(); + } + entry = entry.next; + } + return null; + } + + /** + * Checks whether the map contains the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param key5 the fifth key + * @return true if the map contains the key + */ + public boolean containsKey(final Object key1, final Object key2, final Object key3, + final Object key4, final Object key5) { + final int hashCode = hash(key1, key2, key3, key4, key5); + AbstractHashedMap.HashEntry, V> entry = + decorated().data[decorated().hashIndex(hashCode, decorated().data.length)]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) { + return true; + } + entry = entry.next; + } + return false; + } + + /** + * Stores the value against the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param key5 the fifth key + * @param value the value to store + * @return the value previously mapped to this combined key, null if none + */ + public V put(final K key1, final K key2, final K key3, final K key4, final K key5, final V value) { + final int hashCode = hash(key1, key2, key3, key4, key5); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) { + final V oldValue = entry.getValue(); + decorated().updateEntry(entry, value); + return oldValue; + } + entry = entry.next; + } + decorated().addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4, key5), value); + return null; + } + + /** + * Removes the specified multi-key from this map. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param key5 the fifth key + * @return the value mapped to the removed key, null if key not in map + * @since 4.0 (previous name: remove(Object, Object, Object, Object, Object)) + */ + public V removeMultiKey(final Object key1, final Object key2, final Object key3, + final Object key4, final Object key5) { + final int hashCode = hash(key1, key2, key3, key4, key5); + final int index = decorated().hashIndex(hashCode, decorated().data.length); + AbstractHashedMap.HashEntry, V> entry = decorated().data[index]; + AbstractHashedMap.HashEntry, V> previous = null; + while (entry != null) { + if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) { + final V oldValue = entry.getValue(); + decorated().removeMapping(entry, index, previous); + return oldValue; + } + previous = entry; + entry = entry.next; + } + return null; + } + + /** + * Gets the hash code for the specified multi-key. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param key5 the fifth key + * @return the hash code + */ + protected int hash(final Object key1, final Object key2, final Object key3, final Object key4, final Object key5) { + int h = 0; + if (key1 != null) { + h ^= key1.hashCode(); + } + if (key2 != null) { + h ^= key2.hashCode(); + } + if (key3 != null) { + h ^= key3.hashCode(); + } + if (key4 != null) { + h ^= key4.hashCode(); + } + if (key5 != null) { + h ^= key5.hashCode(); + } + h += ~(h << 9); + h ^= h >>> 14; + h += h << 4; + h ^= h >>> 10; + return h; + } + + /** + * Is the key equal to the combined key. + * + * @param entry the entry to compare to + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @param key5 the fifth key + * @return true if the key matches + */ + protected boolean isEqualKey(final AbstractHashedMap.HashEntry, V> entry, + final Object key1, final Object key2, final Object key3, final Object key4, final Object key5) { + final MultiKey multi = entry.getKey(); + return + multi.size() == 5 && + (key1 == multi.getKey(0) || key1 != null && key1.equals(multi.getKey(0))) && + (key2 == multi.getKey(1) || key2 != null && key2.equals(multi.getKey(1))) && + (key3 == multi.getKey(2) || key3 != null && key3.equals(multi.getKey(2))) && + (key4 == multi.getKey(3) || key4 != null && key4.equals(multi.getKey(3))) && + (key5 == multi.getKey(4) || key5 != null && key5.equals(multi.getKey(4))); + } + + //----------------------------------------------------------------------- + /** + * Removes all mappings where the first key is that specified. + *

              + * This method removes all the mappings where the MultiKey + * has one or more keys, and the first matches that specified. + * + * @param key1 the first key + * @return true if any elements were removed + */ + public boolean removeAll(final Object key1) { + boolean modified = false; + final MapIterator, V> it = mapIterator(); + while (it.hasNext()) { + final MultiKey multi = it.next(); + if (multi.size() >= 1 && + (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0)))) { + it.remove(); + modified = true; + } + } + return modified; + } + + /** + * Removes all mappings where the first two keys are those specified. + *

              + * This method removes all the mappings where the MultiKey + * has two or more keys, and the first two match those specified. + * + * @param key1 the first key + * @param key2 the second key + * @return true if any elements were removed + */ + public boolean removeAll(final Object key1, final Object key2) { + boolean modified = false; + final MapIterator, V> it = mapIterator(); + while (it.hasNext()) { + final MultiKey multi = it.next(); + if (multi.size() >= 2 && + (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) && + (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)))) { + it.remove(); + modified = true; + } + } + return modified; + } + + /** + * Removes all mappings where the first three keys are those specified. + *

              + * This method removes all the mappings where the MultiKey + * has three or more keys, and the first three match those specified. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @return true if any elements were removed + */ + public boolean removeAll(final Object key1, final Object key2, final Object key3) { + boolean modified = false; + final MapIterator, V> it = mapIterator(); + while (it.hasNext()) { + final MultiKey multi = it.next(); + if (multi.size() >= 3 && + (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) && + (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) && + (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)))) { + it.remove(); + modified = true; + } + } + return modified; + } + + /** + * Removes all mappings where the first four keys are those specified. + *

              + * This method removes all the mappings where the MultiKey + * has four or more keys, and the first four match those specified. + * + * @param key1 the first key + * @param key2 the second key + * @param key3 the third key + * @param key4 the fourth key + * @return true if any elements were removed + */ + public boolean removeAll(final Object key1, final Object key2, final Object key3, final Object key4) { + boolean modified = false; + final MapIterator, V> it = mapIterator(); + while (it.hasNext()) { + final MultiKey multi = it.next(); + if (multi.size() >= 4 && + (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) && + (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) && + (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) && + (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)))) { + it.remove(); + modified = true; + } + } + return modified; + } + + //----------------------------------------------------------------------- + /** + * Check to ensure that input keys are valid MultiKey objects. + * + * @param key the key to check + */ + protected void checkKey(final MultiKey key) { + if (key == null) { + throw new NullPointerException("Key must not be null"); + } + } + + /** + * Clones the map without cloning the keys or values. + * + * @return a shallow clone + */ + @SuppressWarnings("unchecked") + @Override + public MultiKeyMap clone() { + try { + return (MultiKeyMap) super.clone(); + } catch (final CloneNotSupportedException e) { + throw new InternalError(); + } + } + + /** + * Puts the key and value into the map, where the key must be a non-null + * MultiKey object. + * + * @param key the non-null MultiKey object + * @param value the value to store + * @return the previous value for the key + * @throws NullPointerException if the key is null + * @throws ClassCastException if the key is not a MultiKey + */ + @Override + public V put(final MultiKey key, final V value) { + checkKey(key); + return super.put(key, value); + } + + /** + * Copies all of the keys and values from the specified map to this map. + * Each key must be non-null and a MultiKey object. + * + * @param mapToCopy to this map + * @throws NullPointerException if the mapToCopy or any key within is null + * @throws ClassCastException if any key in mapToCopy is not a MultiKey + */ + @Override + public void putAll(final Map, ? extends V> mapToCopy) { + for (final MultiKey key : mapToCopy.keySet()) { + checkKey(key); + } + super.putAll(mapToCopy); + } + + //----------------------------------------------------------------------- + @Override + public MapIterator, V> mapIterator() { + return decorated().mapIterator(); + } + + /** + * {@inheritDoc} + */ + @Override + protected AbstractHashedMap, V> decorated() { + return (AbstractHashedMap, V>) super.decorated(); + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map, V>) in.readObject(); + } + +} diff --git a/src/org/apache/commons/collections4/map/MultiValueMap.java b/src/org/apache/commons/collections4/map/MultiValueMap.java new file mode 100644 index 0000000..fbcedd6 --- /dev/null +++ b/src/org/apache/commons/collections4/map/MultiValueMap.java @@ -0,0 +1,577 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.Factory; +import org.apache.commons.collections4.FunctorException; +import org.apache.commons.collections4.MultiMap; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.iterators.EmptyIterator; +import org.apache.commons.collections4.iterators.IteratorChain; +import org.apache.commons.collections4.iterators.LazyIteratorChain; +import org.apache.commons.collections4.iterators.TransformIterator; + +/** + * A MultiValueMap decorates another map, allowing it to have + * more than one value for a key. + *

              + * A MultiMap is a Map with slightly different semantics. + * Putting a value into the map will add the value to a Collection at that key. + * Getting a value will return a Collection, holding all the values put to that key. + *

              + * This implementation is a decorator, allowing any Map implementation + * to be used as the base. + *

              + * In addition, this implementation allows the type of collection used + * for the values to be controlled. By default, an ArrayList + * is used, however a Class to instantiate may be specified, + * or a factory that returns a Collection instance. + *

              + * Note that MultiValueMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. This class may throw exceptions when accessed + * by concurrent threads without synchronization. + * + * @since 3.2 + * @version $Id: MultiValueMap.java 1714360 2015-11-14 20:24:42Z tn $ + * @deprecated since 4.1, use {@link org.apache.commons.collections4.MultiValuedMap MultiValuedMap} instead + */ +@Deprecated +public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = -2214159910087182007L; + + /** The factory for creating value collections. */ + private final Factory> collectionFactory; + /** The cached values. */ + private transient Collection valuesView; + + /** + * Creates a map which wraps the given map and + * maps keys to ArrayLists. + * + * @param the key type + * @param the value type + * @param map the map to wrap + * @return a new multi-value map + * @since 4.0 + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static MultiValueMap multiValueMap(final Map> map) { + return MultiValueMap. multiValueMap((Map) map, ArrayList.class); + } + + /** + * Creates a map which decorates the given map and + * maps keys to collections of type collectionClass. + * + * @param the key type + * @param the value type + * @param the collection class type + * @param map the map to wrap + * @param collectionClass the type of the collection class + * @return a new multi-value map + * @since 4.0 + */ + public static > MultiValueMap multiValueMap(final Map map, + final Class collectionClass) { + return new MultiValueMap(map, new ReflectionFactory(collectionClass)); + } + + /** + * Creates a map which decorates the given map and + * creates the value collections using the supplied collectionFactory. + * + * @param the key type + * @param the value type + * @param the collection class type + * @param map the map to decorate + * @param collectionFactory the collection factory (must return a Collection object). + * @return a new multi-value map + * @since 4.0 + */ + public static > MultiValueMap multiValueMap(final Map map, + final Factory collectionFactory) { + return new MultiValueMap(map, collectionFactory); + } + + //----------------------------------------------------------------------- + /** + * Creates a MultiValueMap based on a HashMap and + * storing the multiple values in an ArrayList. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public MultiValueMap() { + this(new HashMap(), new ReflectionFactory(ArrayList.class)); + } + + /** + * Creates a MultiValueMap which decorates the given map and + * creates the value collections using the supplied collectionFactory. + * + * @param the collection class type + * @param map the map to decorate + * @param collectionFactory the collection factory which must return a Collection instance + */ + @SuppressWarnings("unchecked") + protected > MultiValueMap(final Map map, + final Factory collectionFactory) { + super((Map) map); + if (collectionFactory == null) { + throw new IllegalArgumentException("The factory must not be null"); + } + this.collectionFactory = collectionFactory; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 4.0 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 4.0 + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + //----------------------------------------------------------------------- + /** + * Clear the map. + */ + @Override + public void clear() { + // If you believe that you have GC issues here, try uncommenting this code +// Set pairs = getMap().entrySet(); +// Iterator pairsIterator = pairs.iterator(); +// while (pairsIterator.hasNext()) { +// Map.Entry keyValuePair = (Map.Entry) pairsIterator.next(); +// Collection coll = (Collection) keyValuePair.getValue(); +// coll.clear(); +// } + decorated().clear(); + } + + /** + * Removes a specific value from map. + *

              + * The item is removed from the collection mapped to the specified key. + * Other values attached to that key are unaffected. + *

              + * If the last value for a key is removed, null will be returned + * from a subsequent get(key). + * + * @param key the key to remove from + * @param value the value to remove + * @return {@code true} if the mapping was removed, {@code false} otherwise + */ + @Override + public boolean removeMapping(final Object key, final Object value) { + final Collection valuesForKey = getCollection(key); + if (valuesForKey == null) { + return false; + } + final boolean removed = valuesForKey.remove(value); + if (removed == false) { + return false; + } + if (valuesForKey.isEmpty()) { + remove(key); + } + return true; + } + + /** + * Checks whether the map contains the value specified. + *

              + * This checks all collections against all keys for the value, and thus could be slow. + * + * @param value the value to search for + * @return true if the map contains the value + */ + @Override + @SuppressWarnings("unchecked") + public boolean containsValue(final Object value) { + final Set> pairs = decorated().entrySet(); + if (pairs != null) { + for (final Map.Entry entry : pairs) { + if (((Collection) entry.getValue()).contains(value)) { + return true; + } + } + } + return false; + } + + /** + * Adds the value to the collection associated with the specified key. + *

              + * Unlike a normal Map the previous value is not replaced. + * Instead the new value is added to the collection stored against the key. + * + * @param key the key to store against + * @param value the value to add to the collection at the key + * @return the value added if the map changed and null if the map did not change + */ + @Override + @SuppressWarnings("unchecked") + public Object put(final K key, final Object value) { + boolean result = false; + Collection coll = getCollection(key); + if (coll == null) { + coll = createCollection(1); // might produce a non-empty collection + coll.add((V) value); + if (coll.size() > 0) { + // only add if non-zero size to maintain class state + decorated().put(key, coll); + result = true; // map definitely changed + } + } else { + result = coll.add((V) value); + } + return result ? value : null; + } + + /** + * Override superclass to ensure that MultiMap instances are + * correctly handled. + *

              + * If you call this method with a normal map, each entry is + * added using put(Object,Object). + * If you call this method with a multi map, each entry is + * added using putAll(Object,Collection). + * + * @param map the map to copy (either a normal or multi map) + */ + @Override + @SuppressWarnings("unchecked") + public void putAll(final Map map) { + if (map instanceof MultiMap) { + for (final Map.Entry entry : ((MultiMap) map).entrySet()) { + putAll(entry.getKey(), (Collection) entry.getValue()); + } + } else { + for (final Map.Entry entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + } + + /** + * {@inheritDoc} + *

              + * NOTE: the returned Entry objects will contain as value a {@link Collection} + * of all values that are mapped to the given key. To get a "flattened" version + * of all mappings contained in this map, use {@link #iterator()}. + * + * @see #iterator() + */ + @Override + public Set> entrySet() { + return super.entrySet(); + } + + /** + * Gets a collection containing all the values in the map. + *

              + * This returns a collection containing the combination of values from all keys. + * + * @return a collection view of the values contained in this map + */ + @Override + @SuppressWarnings("unchecked") + public Collection values() { + final Collection vs = valuesView; + return (Collection) (vs != null ? vs : (valuesView = new Values())); + } + + /** + * Checks whether the collection at the specified key contains the value. + * + * @param key the key to search for + * @param value the value to search for + * @return true if the map contains the value + */ + public boolean containsValue(final Object key, final Object value) { + final Collection coll = getCollection(key); + if (coll == null) { + return false; + } + return coll.contains(value); + } + + /** + * Gets the collection mapped to the specified key. + * This method is a convenience method to typecast the result of get(key). + * + * @param key the key to retrieve + * @return the collection mapped to the key, null if no mapping + */ + @SuppressWarnings("unchecked") + public Collection getCollection(final Object key) { + return (Collection) decorated().get(key); + } + + /** + * Gets the size of the collection mapped to the specified key. + * + * @param key the key to get size for + * @return the size of the collection at the key, zero if key not in map + */ + public int size(final Object key) { + final Collection coll = getCollection(key); + if (coll == null) { + return 0; + } + return coll.size(); + } + + /** + * Adds a collection of values to the collection associated with + * the specified key. + * + * @param key the key to store against + * @param values the values to add to the collection at the key, null ignored + * @return true if this map changed + */ + public boolean putAll(final K key, final Collection values) { + if (values == null || values.size() == 0) { + return false; + } + boolean result = false; + Collection coll = getCollection(key); + if (coll == null) { + coll = createCollection(values.size()); // might produce a non-empty collection + coll.addAll(values); + if (coll.size() > 0) { + // only add if non-zero size to maintain class state + decorated().put(key, coll); + result = true; // map definitely changed + } + } else { + result = coll.addAll(values); + } + return result; + } + + /** + * Gets an iterator for the collection mapped to the specified key. + * + * @param key the key to get an iterator for + * @return the iterator of the collection at the key, empty iterator if key not in map + */ + public Iterator iterator(final Object key) { + if (!containsKey(key)) { + return EmptyIterator.emptyIterator(); + } + return new ValuesIterator(key); + } + + /** + * Gets an iterator for all mappings stored in this {@link MultiValueMap}. + *

              + * The iterator will return multiple Entry objects with the same key + * if there are multiple values mapped to this key. + *

              + * NOTE: calling {@link java.util.Map.Entry#setValue(Object)} on any of the returned + * elements will result in a {@link UnsupportedOperationException}. + * + * @return the iterator of all mappings in this map + * @since 4.0 + */ + public Iterator> iterator() { + final Collection allKeys = new ArrayList(keySet()); + final Iterator keyIterator = allKeys.iterator(); + + return new LazyIteratorChain>() { + @Override + protected Iterator> nextIterator(int count) { + if ( ! keyIterator.hasNext() ) { + return null; + } + final K key = keyIterator.next(); + final Transformer> transformer = new Transformer>() { + @Override + public Entry transform(final V input) { + return new Entry() { + @Override + public K getKey() { + return key; + } + @Override + public V getValue() { + return input; + } + @Override + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + }; + } + }; + return new TransformIterator>(new ValuesIterator(key), transformer); + } + }; + } + + /** + * Gets the total size of the map by counting all the values. + * + * @return the total size of the map counting all values + */ + public int totalSize() { + int total = 0; + for (final Object v : decorated().values()) { + total += CollectionUtils.size(v); + } + return total; + } + + /** + * Creates a new instance of the map value Collection container + * using the factory. + *

              + * This method can be overridden to perform your own processing + * instead of using the factory. + * + * @param size the collection size that is about to be added + * @return the new collection + */ + protected Collection createCollection(final int size) { + return collectionFactory.create(); + } + + //----------------------------------------------------------------------- + /** + * Inner class that provides the values view. + */ + private class Values extends AbstractCollection { + @Override + public Iterator iterator() { + final IteratorChain chain = new IteratorChain(); + for (final K k : keySet()) { + chain.addIterator(new ValuesIterator(k)); + } + return chain; + } + + @Override + public int size() { + return totalSize(); + } + + @Override + public void clear() { + MultiValueMap.this.clear(); + } + } + + /** + * Inner class that provides the values iterator. + */ + private class ValuesIterator implements Iterator { + private final Object key; + private final Collection values; + private final Iterator iterator; + + public ValuesIterator(final Object key) { + this.key = key; + this.values = getCollection(key); + this.iterator = values.iterator(); + } + + @Override + public void remove() { + iterator.remove(); + if (values.isEmpty()) { + MultiValueMap.this.remove(key); + } + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public V next() { + return iterator.next(); + } + } + + /** + * Inner class that provides a simple reflection factory. + */ + private static class ReflectionFactory> implements Factory, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 2986114157496788874L; + + private final Class clazz; + + public ReflectionFactory(final Class clazz) { + this.clazz = clazz; + } + + @Override + public T create() { + try { + return clazz.newInstance(); + } catch (final Exception ex) { + throw new FunctorException("Cannot instantiate class: " + clazz, ex); + } + } + + private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { + is.defaultReadObject(); + // ensure that the de-serialized class is a Collection, COLLECTIONS-580 + if (clazz != null && !Collection.class.isAssignableFrom(clazz)) { + throw new UnsupportedOperationException(); + } + } + } + +} diff --git a/src/org/apache/commons/collections4/map/PassiveExpiringMap.java b/src/org/apache/commons/collections4/map/PassiveExpiringMap.java new file mode 100644 index 0000000..647c8d0 --- /dev/null +++ b/src/org/apache/commons/collections4/map/PassiveExpiringMap.java @@ -0,0 +1,538 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Decorates a Map to evict expired entries once their expiration + * time has been reached. + *

              + * When putting a key-value pair in the map this decorator uses a + * {@link ExpirationPolicy} to determine how long the entry should remain alive + * as defined by an expiration time value. + *

              + *

              + * When accessing the mapped value for a key, its expiration time is checked, + * and if it is a negative value or if it is greater than the current time, the + * mapped value is returned. Otherwise, the key is removed from the decorated + * map, and null is returned. + *

              + *

              + * When invoking methods that involve accessing the entire map contents (i.e + * {@link #containsKey(Object)}, {@link #entrySet()}, etc.) this decorator + * removes all expired entries prior to actually completing the invocation. + *

              + *

              + * Note that {@link PassiveExpiringMap} is not synchronized and is not + * thread-safe. If you wish to use this map from multiple threads + * concurrently, you must use appropriate synchronization. The simplest approach + * is to wrap this map using {@link java.util.Collections#synchronizedMap(Map)}. + * This class may throw exceptions when accessed by concurrent threads without + * synchronization. + *

              + * + * @param the type of the keys in the map + * @param the type of the values in the map + * @since 4.0 + * @version $Id: PassiveExpiringMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PassiveExpiringMap + extends AbstractMapDecorator + implements Serializable { + + /** + * A {@link org.apache.commons.collections4.map.PassiveExpiringMap.ExpirationPolicy ExpirationPolicy} + * that returns a expiration time that is a + * constant about of time in the future from the current time. + * + * @param the type of the keys in the map + * @param the type of the values in the map + * @since 4.0 + * @version $Id: PassiveExpiringMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ + public static class ConstantTimeToLiveExpirationPolicy + implements ExpirationPolicy { + + /** Serialization version */ + private static final long serialVersionUID = 1L; + + /** the constant time-to-live value measured in milliseconds. */ + private final long timeToLiveMillis; + + /** + * Default constructor. Constructs a policy using a negative + * time-to-live value that results in entries never expiring. + */ + public ConstantTimeToLiveExpirationPolicy() { + this(-1L); + } + + /** + * Construct a policy with the given time-to-live constant measured in + * milliseconds. A negative time-to-live value indicates entries never + * expire. A zero time-to-live value indicates entries expire (nearly) + * immediately. + * + * @param timeToLiveMillis the constant amount of time (in milliseconds) + * an entry is available before it expires. A negative value + * results in entries that NEVER expire. A zero value results in + * entries that ALWAYS expire. + */ + public ConstantTimeToLiveExpirationPolicy(final long timeToLiveMillis) { + super(); + this.timeToLiveMillis = timeToLiveMillis; + } + + /** + * Construct a policy with the given time-to-live constant measured in + * the given time unit of measure. + * + * @param timeToLive the constant amount of time an entry is available + * before it expires. A negative value results in entries that + * NEVER expire. A zero value results in entries that ALWAYS + * expire. + * @param timeUnit the unit of time for the timeToLive + * parameter, must not be null. + * @throws NullPointerException if the time unit is null. + */ + public ConstantTimeToLiveExpirationPolicy(final long timeToLive, + final TimeUnit timeUnit) { + this(validateAndConvertToMillis(timeToLive, timeUnit)); + } + + /** + * Determine the expiration time for the given key-value entry. + * + * @param key the key for the entry (ignored). + * @param value the value for the entry (ignored). + * @return if {@link #timeToLiveMillis} ≥ 0, an expiration time of + * {@link #timeToLiveMillis} + + * {@link System#currentTimeMillis()} is returned. Otherwise, -1 + * is returned indicating the entry never expires. + */ + public long expirationTime(final K key, final V value) { + if (timeToLiveMillis >= 0L) { + // avoid numerical overflow + final long now = System.currentTimeMillis(); + if (now > Long.MAX_VALUE - timeToLiveMillis) { + // expiration would be greater than Long.MAX_VALUE + // never expire + return -1; + } + + // timeToLiveMillis in the future + return now + timeToLiveMillis; + } + + // never expire + return -1L; + } + } + + /** + * A policy to determine the expiration time for key-value entries. + * + * @param the key object type. + * @param the value object type + * @since 4.0 + * @version $Id: PassiveExpiringMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ + public static interface ExpirationPolicy + extends Serializable { + + /** + * Determine the expiration time for the given key-value entry. + * + * @param key the key for the entry. + * @param value the value for the entry. + * @return the expiration time value measured in milliseconds. A + * negative return value indicates the entry never expires. + */ + long expirationTime(K key, V value); + } + + /** Serialization version */ + private static final long serialVersionUID = 1L; + + /** + * First validate the input parameters. If the parameters are valid, convert + * the given time measured in the given units to the same time measured in + * milliseconds. + * + * @param timeToLive the constant amount of time an entry is available + * before it expires. A negative value results in entries that NEVER + * expire. A zero value results in entries that ALWAYS expire. + * @param timeUnit the unit of time for the timeToLive + * parameter, must not be null. + * @throws NullPointerException if the time unit is null. + */ + private static long validateAndConvertToMillis(final long timeToLive, + final TimeUnit timeUnit) { + if (timeUnit == null) { + throw new NullPointerException("Time unit must not be null"); + } + return TimeUnit.MILLISECONDS.convert(timeToLive, timeUnit); + } + + /** map used to manage expiration times for the actual map entries. */ + private final Map expirationMap = new HashMap(); + + /** the policy used to determine time-to-live values for map entries. */ + private final ExpirationPolicy expiringPolicy; + + /** + * Default constructor. Constructs a map decorator that results in entries + * NEVER expiring. + */ + public PassiveExpiringMap() { + this(-1L); + } + + /** + * Construct a map decorator using the given expiration policy to determine + * expiration times. + * + * @param expiringPolicy the policy used to determine expiration times of + * entries as they are added. + * @throws NullPointerException if expiringPolicy is null + */ + public PassiveExpiringMap(final ExpirationPolicy expiringPolicy) { + this(expiringPolicy, new HashMap()); + } + + /** + * Construct a map decorator that decorates the given map and uses the given + * expiration policy to determine expiration times. If there are any + * elements already in the map being decorated, they will NEVER expire + * unless they are replaced. + * + * @param expiringPolicy the policy used to determine expiration times of + * entries as they are added. + * @param map the map to decorate, must not be null. + * @throws NullPointerException if the map or expiringPolicy is null. + */ + public PassiveExpiringMap(final ExpirationPolicy expiringPolicy, + final Map map) { + super(map); + if (expiringPolicy == null) { + throw new NullPointerException("Policy must not be null."); + } + this.expiringPolicy = expiringPolicy; + } + + /** + * Construct a map decorator that decorates the given map using the given + * time-to-live value measured in milliseconds to create and use a + * {@link ConstantTimeToLiveExpirationPolicy} expiration policy. + * + * @param timeToLiveMillis the constant amount of time (in milliseconds) an + * entry is available before it expires. A negative value results in + * entries that NEVER expire. A zero value results in entries that + * ALWAYS expire. + */ + public PassiveExpiringMap(final long timeToLiveMillis) { + this(new ConstantTimeToLiveExpirationPolicy(timeToLiveMillis), + new HashMap()); + } + + /** + * Construct a map decorator using the given time-to-live value measured in + * milliseconds to create and use a + * {@link ConstantTimeToLiveExpirationPolicy} expiration policy. If there + * are any elements already in the map being decorated, they will NEVER + * expire unless they are replaced. + * + * @param timeToLiveMillis the constant amount of time (in milliseconds) an + * entry is available before it expires. A negative value results in + * entries that NEVER expire. A zero value results in entries that + * ALWAYS expire. + * @param map the map to decorate, must not be null. + * @throws NullPointerException if the map is null. + */ + public PassiveExpiringMap(final long timeToLiveMillis, final Map map) { + this(new ConstantTimeToLiveExpirationPolicy(timeToLiveMillis), + map); + } + + /** + * Construct a map decorator using the given time-to-live value measured in + * the given time units of measure to create and use a + * {@link ConstantTimeToLiveExpirationPolicy} expiration policy. + * + * @param timeToLive the constant amount of time an entry is available + * before it expires. A negative value results in entries that NEVER + * expire. A zero value results in entries that ALWAYS expire. + * @param timeUnit the unit of time for the timeToLive + * parameter, must not be null. + * @throws NullPointerException if the time unit is null. + */ + public PassiveExpiringMap(final long timeToLive, final TimeUnit timeUnit) { + this(validateAndConvertToMillis(timeToLive, timeUnit)); + } + + /** + * Construct a map decorator that decorates the given map using the given + * time-to-live value measured in the given time units of measure to create + * {@link ConstantTimeToLiveExpirationPolicy} expiration policy. This policy + * is used to determine expiration times. If there are any elements already + * in the map being decorated, they will NEVER expire unless they are + * replaced. + * + * @param timeToLive the constant amount of time an entry is available + * before it expires. A negative value results in entries that NEVER + * expire. A zero value results in entries that ALWAYS expire. + * @param timeUnit the unit of time for the timeToLive + * parameter, must not be null. + * @param map the map to decorate, must not be null. + * @throws NullPointerException if the map or time unit is null. + */ + public PassiveExpiringMap(final long timeToLive, final TimeUnit timeUnit, final Map map) { + this(validateAndConvertToMillis(timeToLive, timeUnit), map); + } + + /** + * Constructs a map decorator that decorates the given map and results in + * entries NEVER expiring. If there are any elements already in the map + * being decorated, they also will NEVER expire. + * + * @param map the map to decorate, must not be null. + * @throws NullPointerException if the map is null. + */ + public PassiveExpiringMap(final Map map) { + this(-1L, map); + } + + /** + * Normal {@link Map#clear()} behavior with the addition of clearing all + * expiration entries as well. + */ + @Override + public void clear() { + super.clear(); + expirationMap.clear(); + } + + /** + * All expired entries are removed from the map prior to determining the + * contains result. + * {@inheritDoc} + */ + @Override + public boolean containsKey(final Object key) { + removeIfExpired(key, now()); + return super.containsKey(key); + } + + /** + * All expired entries are removed from the map prior to determining the + * contains result. + * {@inheritDoc} + */ + @Override + public boolean containsValue(final Object value) { + removeAllExpired(now()); + return super.containsValue(value); + } + + /** + * All expired entries are removed from the map prior to returning the entry set. + * {@inheritDoc} + */ + @Override + public Set> entrySet() { + removeAllExpired(now()); + return super.entrySet(); + } + + /** + * All expired entries are removed from the map prior to returning the entry value. + * {@inheritDoc} + */ + @Override + public V get(final Object key) { + removeIfExpired(key, now()); + return super.get(key); + } + + /** + * All expired entries are removed from the map prior to determining if it is empty. + * {@inheritDoc} + */ + @Override + public boolean isEmpty() { + removeAllExpired(now()); + return super.isEmpty(); + } + + /** + * Determines if the given expiration time is less than now. + * + * @param now the time in milliseconds used to compare against the + * expiration time. + * @param expirationTimeObject the expiration time value retrieved from + * {@link #expirationMap}, can be null. + * @return true if expirationTimeObject is ≥ 0 + * and expirationTimeObject < now. + * false otherwise. + */ + private boolean isExpired(final long now, final Long expirationTimeObject) { + if (expirationTimeObject != null) { + final long expirationTime = expirationTimeObject.longValue(); + return expirationTime >= 0 && now >= expirationTime; + } + return false; + } + + /** + * All expired entries are removed from the map prior to returning the key set. + * {@inheritDoc} + */ + @Override + public Set keySet() { + removeAllExpired(now()); + return super.keySet(); + } + + /** + * The current time in milliseconds. + */ + private long now() { + return System.currentTimeMillis(); + } + + /** + * Add the given key-value pair to this map as well as recording the entry's expiration time based on + * the current time in milliseconds and this map's {@link #expiringPolicy}. + *

              + * {@inheritDoc} + */ + @Override + public V put(final K key, final V value) { + // record expiration time of new entry + final long expirationTime = expiringPolicy.expirationTime(key, value); + expirationMap.put(key, Long.valueOf(expirationTime)); + + return super.put(key, value); + } + + @Override + public void putAll(final Map mapToCopy) { + for (final Map.Entry entry : mapToCopy.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + /** + * Normal {@link Map#remove(Object)} behavior with the addition of removing + * any expiration entry as well. + * {@inheritDoc} + */ + @Override + public V remove(final Object key) { + expirationMap.remove(key); + return super.remove(key); + } + + /** + * Removes all entries in the map whose expiration time is less than + * now. The exceptions are entries with negative expiration + * times; those entries are never removed. + * + * @see #isExpired(long, Long) + */ + private void removeAllExpired(final long now) { + final Iterator> iter = expirationMap.entrySet().iterator(); + while (iter.hasNext()) { + final Map.Entry expirationEntry = iter.next(); + if (isExpired(now, expirationEntry.getValue())) { + // remove entry from collection + super.remove(expirationEntry.getKey()); + // remove entry from expiration map + iter.remove(); + } + } + } + + /** + * Removes the entry with the given key if the entry's expiration time is + * less than now. If the entry has a negative expiration time, + * the entry is never removed. + */ + private void removeIfExpired(final Object key, final long now) { + final Long expirationTimeObject = expirationMap.get(key); + if (isExpired(now, expirationTimeObject)) { + remove(key); + } + } + + /** + * All expired entries are removed from the map prior to returning the size. + * {@inheritDoc} + */ + @Override + public int size() { + removeAllExpired(now()); + return super.size(); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") + // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) + throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) + throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * All expired entries are removed from the map prior to returning the value collection. + * {@inheritDoc} + */ + @Override + public Collection values() { + removeAllExpired(now()); + return super.values(); + } +} diff --git a/src/org/apache/commons/collections4/map/PredicatedMap.java b/src/org/apache/commons/collections4/map/PredicatedMap.java new file mode 100644 index 0000000..1ec1818 --- /dev/null +++ b/src/org/apache/commons/collections4/map/PredicatedMap.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.collections4.Predicate; + +/** + * Decorates another Map to validate that additions + * match a specified predicate. + *

              + * This map exists to provide validation for the decorated map. + * It is normally created to decorate an empty map. + * If an object cannot be added to the map, an IllegalArgumentException is thrown. + *

              + * One usage would be to ensure that no null keys are added to the map. + *

              Map map = PredicatedSet.decorate(new HashMap(), NotNullPredicate.INSTANCE, null);
              + *

              + * Note that PredicatedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: PredicatedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedMap + extends AbstractInputCheckedMapDecorator + implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 7412622456128415156L; + + /** The key predicate to use */ + protected final Predicate keyPredicate; + + /** The value predicate to use */ + protected final Predicate valuePredicate; + + /** + * Factory method to create a predicated (validating) map. + *

              + * If there are any elements already in the list being decorated, they + * are validated. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param keyPredicate the predicate to validate the keys, null means no check + * @param valuePredicate the predicate to validate to values, null means no check + * @return a new predicated map + * @throws NullPointerException if the map is null + * @since 4.0 + */ + public static PredicatedMap predicatedMap(final Map map, + final Predicate keyPredicate, + final Predicate valuePredicate) { + return new PredicatedMap(map, keyPredicate, valuePredicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param keyPredicate the predicate to validate the keys, null means no check + * @param valuePredicate the predicate to validate to values, null means no check + * @throws NullPointerException if the map is null + */ + protected PredicatedMap(final Map map, final Predicate keyPredicate, + final Predicate valuePredicate) { + super(map); + this.keyPredicate = keyPredicate; + this.valuePredicate = valuePredicate; + + final Iterator> it = map.entrySet().iterator(); + while (it.hasNext()) { + final Map.Entry entry = it.next(); + validate(entry.getKey(), entry.getValue()); + } + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + //----------------------------------------------------------------------- + /** + * Validates a key value pair. + * + * @param key the key to validate + * @param value the value to validate + * @throws IllegalArgumentException if invalid + */ + protected void validate(final K key, final V value) { + if (keyPredicate != null && keyPredicate.evaluate(key) == false) { + throw new IllegalArgumentException("Cannot add key - Predicate rejected it"); + } + if (valuePredicate != null && valuePredicate.evaluate(value) == false) { + throw new IllegalArgumentException("Cannot add value - Predicate rejected it"); + } + } + + /** + * Override to validate an object set into the map via setValue. + * + * @param value the value to validate + * @return the value itself + * @throws IllegalArgumentException if invalid + * @since 3.1 + */ + @Override + protected V checkSetValue(final V value) { + if (valuePredicate.evaluate(value) == false) { + throw new IllegalArgumentException("Cannot set value - Predicate rejected it"); + } + return value; + } + + /** + * Override to only return true when there is a value transformer. + * + * @return true if a value predicate is in use + * @since 3.1 + */ + @Override + protected boolean isSetValueChecking() { + return valuePredicate != null; + } + + //----------------------------------------------------------------------- + @Override + public V put(final K key, final V value) { + validate(key, value); + return map.put(key, value); + } + + @Override + public void putAll(final Map mapToCopy) { + for (final Map.Entry entry : mapToCopy.entrySet()) { + validate(entry.getKey(), entry.getValue()); + } + super.putAll(mapToCopy); + } + +} diff --git a/src/org/apache/commons/collections4/map/PredicatedSortedMap.java b/src/org/apache/commons/collections4/map/PredicatedSortedMap.java new file mode 100644 index 0000000..96b2257 --- /dev/null +++ b/src/org/apache/commons/collections4/map/PredicatedSortedMap.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.Comparator; +import java.util.SortedMap; + +import org.apache.commons.collections4.Predicate; + +/** + * Decorates another SortedMap to validate that additions + * match a specified predicate. + *

              + * This map exists to provide validation for the decorated map. + * It is normally created to decorate an empty map. + * If an object cannot be added to the map, an IllegalArgumentException is thrown. + *

              + * One usage would be to ensure that no null keys are added to the map. + *

              + *   SortedMap map =
              + *     PredicatedSortedMap.predicatedSortedMap(new TreeMap(),
              + *                                             NotNullPredicate.notNullPredicate(),
              + *                                             null);
              + * 
              + *

              + * Note that PredicatedSortedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedSortedMap}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: PredicatedSortedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedSortedMap extends PredicatedMap implements SortedMap { + + /** Serialization version */ + private static final long serialVersionUID = 3359846175935304332L; + + /** + * Factory method to create a predicated (validating) sorted map. + *

              + * If there are any elements already in the list being decorated, they + * are validated. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param keyPredicate the predicate to validate the keys, null means no check + * @param valuePredicate the predicate to validate to values, null means no check + * @return a new predicated sorted map + * @throws NullPointerException if the map is null + * @since 4.0 + */ + public static PredicatedSortedMap predicatedSortedMap(final SortedMap map, + final Predicate keyPredicate, final Predicate valuePredicate) { + return new PredicatedSortedMap(map, keyPredicate, valuePredicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param keyPredicate the predicate to validate the keys, null means no check + * @param valuePredicate the predicate to validate to values, null means no check + * @throws NullPointerException if the map is null + */ + protected PredicatedSortedMap(final SortedMap map, final Predicate keyPredicate, + final Predicate valuePredicate) { + super(map, keyPredicate, valuePredicate); + } + + //----------------------------------------------------------------------- + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + protected SortedMap getSortedMap() { + return (SortedMap) map; + } + + //----------------------------------------------------------------------- + public K firstKey() { + return getSortedMap().firstKey(); + } + + public K lastKey() { + return getSortedMap().lastKey(); + } + + public Comparator comparator() { + return getSortedMap().comparator(); + } + + public SortedMap subMap(final K fromKey, final K toKey) { + final SortedMap map = getSortedMap().subMap(fromKey, toKey); + return new PredicatedSortedMap(map, keyPredicate, valuePredicate); + } + + public SortedMap headMap(final K toKey) { + final SortedMap map = getSortedMap().headMap(toKey); + return new PredicatedSortedMap(map, keyPredicate, valuePredicate); + } + + public SortedMap tailMap(final K fromKey) { + final SortedMap map = getSortedMap().tailMap(fromKey); + return new PredicatedSortedMap(map, keyPredicate, valuePredicate); + } + +} diff --git a/src/org/apache/commons/collections4/map/ReferenceIdentityMap.java b/src/org/apache/commons/collections4/map/ReferenceIdentityMap.java new file mode 100644 index 0000000..3b894a0 --- /dev/null +++ b/src/org/apache/commons/collections4/map/ReferenceIdentityMap.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.ref.Reference; + +/** + * A Map implementation that allows mappings to be + * removed by the garbage collector and matches keys and values based + * on == not equals(). + *

              + *

              + * When you construct a ReferenceIdentityMap, you can specify what kind + * of references are used to store the map's keys and values. + * If non-hard references are used, then the garbage collector can remove + * mappings if a key or value becomes unreachable, or if the JVM's memory is + * running low. For information on how the different reference types behave, + * see {@link Reference}. + *

              + * Different types of references can be specified for keys and values. + * The default constructor uses hard keys and soft values, providing a + * memory-sensitive cache. + *

              + * This map is similar to + * {@link org.apache.commons.collections4.map.ReferenceMap ReferenceMap}. + * It differs in that keys and values in this class are compared using ==. + *

              + * This map will violate the detail of various Map and map view contracts. + * As a general rule, don't compare this map to other maps. + *

              + * This {@link java.util.Map Map} implementation does not allow null elements. + * Attempting to add a null key or value to the map will raise a NullPointerException. + *

              + * This implementation is not synchronized. + * You can use {@link java.util.Collections#synchronizedMap} to + * provide synchronized access to a ReferenceIdentityMap. + * Remember that synchronization will not stop the garbage collector removing entries. + *

              + * All the available iterators can be reset back to the start by casting to + * ResettableIterator and calling reset(). + *

              + * Note that ReferenceIdentityMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @see java.lang.ref.Reference + * + * @since 3.0 (previously in main package v2.1) + * @version $Id: ReferenceIdentityMap.java 1477799 2013-04-30 19:56:11Z tn $ + */ +public class ReferenceIdentityMap extends AbstractReferenceMap implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = -1266190134568365852L; + + /** + * Constructs a new ReferenceIdentityMap that will + * use hard references to keys and soft references to values. + */ + public ReferenceIdentityMap() { + super(ReferenceStrength.HARD, ReferenceStrength.SOFT, DEFAULT_CAPACITY, + DEFAULT_LOAD_FACTOR, false); + } + + /** + * Constructs a new ReferenceIdentityMap that will + * use the specified types of references. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + */ + public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType) { + super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false); + } + + /** + * Constructs a new ReferenceIdentityMap that will + * use the specified types of references. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param purgeValues should the value be automatically purged when the + * key is garbage collected + */ + public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType, + final boolean purgeValues) { + super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, purgeValues); + } + + /** + * Constructs a new ReferenceIdentityMap with the + * specified reference types, load factor and initial capacity. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param capacity the initial capacity for the map + * @param loadFactor the load factor for the map + */ + public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType, + final int capacity, final float loadFactor) { + super(keyType, valueType, capacity, loadFactor, false); + } + + /** + * Constructs a new ReferenceIdentityMap with the + * specified reference types, load factor and initial capacity. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param capacity the initial capacity for the map + * @param loadFactor the load factor for the map + * @param purgeValues should the value be automatically purged when the + * key is garbage collected + */ + public ReferenceIdentityMap(final ReferenceStrength keyType, final ReferenceStrength valueType, + final int capacity, final float loadFactor, final boolean purgeValues) { + super(keyType, valueType, capacity, loadFactor, purgeValues); + } + + //----------------------------------------------------------------------- + /** + * Gets the hash code for the key specified. + *

              + * This implementation uses the identity hash code. + * + * @param key the key to get a hash code for + * @return the hash code + */ + @Override + protected int hash(final Object key) { + return System.identityHashCode(key); + } + + /** + * Gets the hash code for a MapEntry. + *

              + * This implementation uses the identity hash code. + * + * @param key the key to get a hash code for, may be null + * @param value the value to get a hash code for, may be null + * @return the hash code, as per the MapEntry specification + */ + @Override + protected int hashEntry(final Object key, final Object value) { + return System.identityHashCode(key) ^ + System.identityHashCode(value); + } + + /** + * Compares two keys for equals. + *

              + * This implementation converts the key from the entry to a real reference + * before comparison and uses ==. + * + * @param key1 the first key to compare passed in from outside + * @param key2 the second key extracted from the entry via entry.key + * @return true if equal by identity + */ + @Override + protected boolean isEqualKey(final Object key1, Object key2) { + key2 = isKeyType(ReferenceStrength.HARD) ? key2 : ((Reference) key2).get(); + return key1 == key2; + } + + /** + * Compares two values for equals. + *

              + * This implementation uses ==. + * + * @param value1 the first value to compare passed in from outside + * @param value2 the second value extracted from the entry via getValue() + * @return true if equal by identity + */ + @Override + protected boolean isEqualValue(final Object value1, final Object value2) { + return value1 == value2; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Read the map in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + +} diff --git a/src/org/apache/commons/collections4/map/ReferenceMap.java b/src/org/apache/commons/collections4/map/ReferenceMap.java new file mode 100644 index 0000000..9b8de01 --- /dev/null +++ b/src/org/apache/commons/collections4/map/ReferenceMap.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * A Map implementation that allows mappings to be + * removed by the garbage collector. + *

              + * When you construct a ReferenceMap, you can specify what kind + * of references are used to store the map's keys and values. + * If non-hard references are used, then the garbage collector can remove + * mappings if a key or value becomes unreachable, or if the JVM's memory is + * running low. For information on how the different reference types behave, + * see {@link java.lang.ref.Reference Reference}. + *

              + * Different types of references can be specified for keys and values. + * The keys can be configured to be weak but the values hard, + * in which case this class will behave like a + * + * WeakHashMap. However, you can also specify hard keys and + * weak values, or any other combination. The default constructor uses + * hard keys and soft values, providing a memory-sensitive cache. + *

              + * This map is similar to + * {@link org.apache.commons.collections4.map.ReferenceIdentityMap ReferenceIdentityMap}. + * It differs in that keys and values in this class are compared using equals(). + *

              + * This {@link java.util.Map Map} implementation does not allow null elements. + * Attempting to add a null key or value to the map will raise a NullPointerException. + *

              + * This implementation is not synchronized. + * You can use {@link java.util.Collections#synchronizedMap} to + * provide synchronized access to a ReferenceMap. + * Remember that synchronization will not stop the garbage collector removing entries. + *

              + * All the available iterators can be reset back to the start by casting to + * ResettableIterator and calling reset(). + *

              + * Note that ReferenceMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * NOTE: As from Commons Collections 3.1 this map extends AbstractReferenceMap + * (previously it extended AbstractMap). As a result, the implementation is now + * extensible and provides a MapIterator. + * + * @see java.lang.ref.Reference + * + * @since 3.0 (previously in main package v2.1) + * @version $Id: ReferenceMap.java 1477799 2013-04-30 19:56:11Z tn $ + */ +public class ReferenceMap extends AbstractReferenceMap implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 1555089888138299607L; + + /** + * Constructs a new ReferenceMap that will + * use hard references to keys and soft references to values. + */ + public ReferenceMap() { + super(ReferenceStrength.HARD, ReferenceStrength.SOFT, DEFAULT_CAPACITY, + DEFAULT_LOAD_FACTOR, false); + } + + /** + * Constructs a new ReferenceMap that will + * use the specified types of references. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + */ + public ReferenceMap(final ReferenceStrength keyType, final ReferenceStrength valueType) { + super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false); + } + + /** + * Constructs a new ReferenceMap that will + * use the specified types of references. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param purgeValues should the value be automatically purged when the + * key is garbage collected + */ + public ReferenceMap(final ReferenceStrength keyType, final ReferenceStrength valueType, final boolean purgeValues) { + super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, purgeValues); + } + + /** + * Constructs a new ReferenceMap with the + * specified reference types, load factor and initial + * capacity. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param capacity the initial capacity for the map + * @param loadFactor the load factor for the map + */ + public ReferenceMap(final ReferenceStrength keyType, final ReferenceStrength valueType, final int capacity, + final float loadFactor) { + super(keyType, valueType, capacity, loadFactor, false); + } + + /** + * Constructs a new ReferenceMap with the + * specified reference types, load factor and initial + * capacity. + * + * @param keyType the type of reference to use for keys; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param valueType the type of reference to use for values; + * must be {@link AbstractReferenceMap.ReferenceStrength#HARD HARD}, + * {@link AbstractReferenceMap.ReferenceStrength#SOFT SOFT}, + * {@link AbstractReferenceMap.ReferenceStrength#WEAK WEAK} + * @param capacity the initial capacity for the map + * @param loadFactor the load factor for the map + * @param purgeValues should the value be automatically purged when the + * key is garbage collected + */ + public ReferenceMap(final ReferenceStrength keyType, final ReferenceStrength valueType, final int capacity, + final float loadFactor, final boolean purgeValues) { + super(keyType, valueType, capacity, loadFactor, purgeValues); + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Read the map in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + +} diff --git a/src/org/apache/commons/collections4/map/SingletonMap.java b/src/org/apache/commons/collections4/map/SingletonMap.java new file mode 100644 index 0000000..9577506 --- /dev/null +++ b/src/org/apache/commons/collections4/map/SingletonMap.java @@ -0,0 +1,576 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.Serializable; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.apache.commons.collections4.BoundedMap; +import org.apache.commons.collections4.KeyValue; +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.ResettableIterator; +import org.apache.commons.collections4.iterators.SingletonIterator; +import org.apache.commons.collections4.keyvalue.TiedMapEntry; + +/** + * A Map implementation that holds a single item and is fixed size. + *

              + * The single key/value pair is specified at creation. + * The map is fixed size so any action that would change the size is disallowed. + * However, the put or setValue methods can change + * the value associated with the key. + *

              + * If trying to remove or clear the map, an UnsupportedOperationException is thrown. + * If trying to put a new mapping into the map, an IllegalArgumentException is thrown. + * The put method will only succeed if the key specified is the same as the + * singleton key. + *

              + * The key and value can be obtained by: + *

                + *
              • normal Map methods and views + *
              • the MapIterator, see {@link #mapIterator()} + *
              • the KeyValue interface (just cast - no object creation) + *
              + * + * @since 3.1 + * @version $Id: SingletonMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class SingletonMap + implements OrderedMap, BoundedMap, KeyValue, Serializable, Cloneable { + + /** Serialization version */ + private static final long serialVersionUID = -8931271118676803261L; + + /** Singleton key */ + private final K key; + /** Singleton value */ + private V value; + + /** + * Constructor that creates a map of null to null. + */ + public SingletonMap() { + super(); + this.key = null; + } + + /** + * Constructor specifying the key and value. + * + * @param key the key to use + * @param value the value to use + */ + public SingletonMap(final K key, final V value) { + super(); + this.key = key; + this.value = value; + } + + /** + * Constructor specifying the key and value as a KeyValue. + * + * @param keyValue the key value pair to use + */ + public SingletonMap(final KeyValue keyValue) { + super(); + this.key = keyValue.getKey(); + this.value = keyValue.getValue(); + } + + /** + * Constructor specifying the key and value as a MapEntry. + * + * @param mapEntry the mapEntry to use + */ + public SingletonMap(final Map.Entry mapEntry) { + super(); + this.key = mapEntry.getKey(); + this.value = mapEntry.getValue(); + } + + /** + * Constructor copying elements from another map. + * + * @param map the map to copy, must be size 1 + * @throws NullPointerException if the map is null + * @throws IllegalArgumentException if the size is not 1 + */ + public SingletonMap(final Map map) { + super(); + if (map.size() != 1) { + throw new IllegalArgumentException("The map size must be 1"); + } + final Map.Entry entry = map.entrySet().iterator().next(); + this.key = entry.getKey(); + this.value = entry.getValue(); + } + + // KeyValue + //----------------------------------------------------------------------- + /** + * Gets the key. + * + * @return the key + */ + public K getKey() { + return key; + } + + /** + * Gets the value. + * + * @return the value + */ + public V getValue() { + return value; + } + + /** + * Sets the value. + * + * @param value the new value to set + * @return the old value + */ + public V setValue(final V value) { + final V old = this.value; + this.value = value; + return old; + } + + // BoundedMap + //----------------------------------------------------------------------- + /** + * Is the map currently full, always true. + * + * @return true always + */ + public boolean isFull() { + return true; + } + + /** + * Gets the maximum size of the map, always 1. + * + * @return 1 always + */ + public int maxSize() { + return 1; + } + + // Map + //----------------------------------------------------------------------- + /** + * Gets the value mapped to the key specified. + * + * @param key the key + * @return the mapped value, null if no match + */ + public V get(final Object key) { + if (isEqualKey(key)) { + return value; + } + return null; + } + + /** + * Gets the size of the map, always 1. + * + * @return the size of 1 + */ + public int size() { + return 1; + } + + /** + * Checks whether the map is currently empty, which it never is. + * + * @return false always + */ + public boolean isEmpty() { + return false; + } + + //----------------------------------------------------------------------- + /** + * Checks whether the map contains the specified key. + * + * @param key the key to search for + * @return true if the map contains the key + */ + public boolean containsKey(final Object key) { + return isEqualKey(key); + } + + /** + * Checks whether the map contains the specified value. + * + * @param value the value to search for + * @return true if the map contains the key + */ + public boolean containsValue(final Object value) { + return isEqualValue(value); + } + + //----------------------------------------------------------------------- + /** + * Puts a key-value mapping into this map where the key must match the existing key. + *

              + * An IllegalArgumentException is thrown if the key does not match as the map + * is fixed size. + * + * @param key the key to set, must be the key of the map + * @param value the value to set + * @return the value previously mapped to this key, null if none + * @throws IllegalArgumentException if the key does not match + */ + public V put(final K key, final V value) { + if (isEqualKey(key)) { + return setValue(value); + } + throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size singleton"); + } + + /** + * Puts the values from the specified map into this map. + *

              + * The map must be of size 0 or size 1. + * If it is size 1, the key must match the key of this map otherwise an + * IllegalArgumentException is thrown. + * + * @param map the map to add, must be size 0 or 1, and the key must match + * @throws NullPointerException if the map is null + * @throws IllegalArgumentException if the key does not match + */ + public void putAll(final Map map) { + switch (map.size()) { + case 0: + return; + + case 1: + final Map.Entry entry = map.entrySet().iterator().next(); + put(entry.getKey(), entry.getValue()); + return; + + default: + throw new IllegalArgumentException("The map size must be 0 or 1"); + } + } + + /** + * Unsupported operation. + * + * @param key the mapping to remove + * @return the value mapped to the removed key, null if key not in map + * @throws UnsupportedOperationException always + */ + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + /** + * Unsupported operation. + */ + public void clear() { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + /** + * Gets the entrySet view of the map. + * Changes made via setValue affect this map. + * To simply iterate through the entries, use {@link #mapIterator()}. + * + * @return the entrySet view + */ + public Set> entrySet() { + final Map.Entry entry = new TiedMapEntry(this, getKey()); + return Collections.singleton(entry); + } + + /** + * Gets the unmodifiable keySet view of the map. + * Changes made to the view affect this map. + * To simply iterate through the keys, use {@link #mapIterator()}. + * + * @return the keySet view + */ + public Set keySet() { + return Collections.singleton(key); + } + + /** + * Gets the unmodifiable values view of the map. + * Changes made to the view affect this map. + * To simply iterate through the values, use {@link #mapIterator()}. + * + * @return the values view + */ + public Collection values() { + return new SingletonValues(this); + } + + /** + * {@inheritDoc} + */ + public OrderedMapIterator mapIterator() { + return new SingletonMapIterator(this); + } + + /** + * Gets the first (and only) key in the map. + * + * @return the key + */ + public K firstKey() { + return getKey(); + } + + /** + * Gets the last (and only) key in the map. + * + * @return the key + */ + public K lastKey() { + return getKey(); + } + + /** + * Gets the next key after the key specified, always null. + * + * @param key the next key + * @return null always + */ + public K nextKey(final K key) { + return null; + } + + /** + * Gets the previous key before the key specified, always null. + * + * @param key the next key + * @return null always + */ + public K previousKey(final K key) { + return null; + } + + //----------------------------------------------------------------------- + /** + * Compares the specified key to the stored key. + * + * @param key the key to compare + * @return true if equal + */ + protected boolean isEqualKey(final Object key) { + return key == null ? getKey() == null : key.equals(getKey()); + } + + /** + * Compares the specified value to the stored value. + * + * @param value the value to compare + * @return true if equal + */ + protected boolean isEqualValue(final Object value) { + return value == null ? getValue() == null : value.equals(getValue()); + } + + //----------------------------------------------------------------------- + /** + * SingletonMapIterator. + */ + static class SingletonMapIterator implements OrderedMapIterator, ResettableIterator { + private final SingletonMap parent; + private boolean hasNext = true; + private boolean canGetSet = false; + + SingletonMapIterator(final SingletonMap parent) { + super(); + this.parent = parent; + } + + public boolean hasNext() { + return hasNext; + } + + public K next() { + if (hasNext == false) { + throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY); + } + hasNext = false; + canGetSet = true; + return parent.getKey(); + } + + public boolean hasPrevious() { + return hasNext == false; + } + + public K previous() { + if (hasNext == true) { + throw new NoSuchElementException(AbstractHashedMap.NO_PREVIOUS_ENTRY); + } + hasNext = true; + return parent.getKey(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + + public K getKey() { + if (canGetSet == false) { + throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID); + } + return parent.getKey(); + } + + public V getValue() { + if (canGetSet == false) { + throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID); + } + return parent.getValue(); + } + + public V setValue(final V value) { + if (canGetSet == false) { + throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID); + } + return parent.setValue(value); + } + + public void reset() { + hasNext = true; + } + + @Override + public String toString() { + if (hasNext) { + return "Iterator[]"; + } + return "Iterator[" + getKey() + "=" + getValue() + "]"; + } + } + + /** + * Values implementation for the SingletonMap. + * This class is needed as values is a view that must update as the map updates. + */ + static class SingletonValues extends AbstractSet implements Serializable { + private static final long serialVersionUID = -3689524741863047872L; + private final SingletonMap parent; + + SingletonValues(final SingletonMap parent) { + super(); + this.parent = parent; + } + + @Override + public int size() { + return 1; + } + @Override + public boolean isEmpty() { + return false; + } + @Override + public boolean contains(final Object object) { + return parent.containsValue(object); + } + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + @Override + public Iterator iterator() { + return new SingletonIterator(parent.getValue(), false); + } + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the key or value. + * + * @return a shallow clone + */ + @Override + @SuppressWarnings("unchecked") + public SingletonMap clone() { + try { + return (SingletonMap) super.clone(); + } catch (final CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + /** + * Compares this map with another. + * + * @param obj the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map == false) { + return false; + } + final Map other = (Map) obj; + if (other.size() != 1) { + return false; + } + final Map.Entry entry = other.entrySet().iterator().next(); + return isEqualKey(entry.getKey()) && isEqualValue(entry.getValue()); + } + + /** + * Gets the standard Map hashCode. + * + * @return the hash code defined in the Map interface + */ + @Override + public int hashCode() { + return (getKey() == null ? 0 : getKey().hashCode()) ^ + (getValue() == null ? 0 : getValue().hashCode()); + } + + /** + * Gets the map as a String. + * + * @return a string version of the map + */ + @Override + public String toString() { + return new StringBuilder(128) + .append('{') + .append(getKey() == this ? "(this Map)" : getKey()) + .append('=') + .append(getValue() == this ? "(this Map)" : getValue()) + .append('}') + .toString(); + } + +} diff --git a/src/org/apache/commons/collections4/map/StaticBucketMap.java b/src/org/apache/commons/collections4/map/StaticBucketMap.java new file mode 100644 index 0000000..1a8433e --- /dev/null +++ b/src/org/apache/commons/collections4/map/StaticBucketMap.java @@ -0,0 +1,718 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.apache.commons.collections4.KeyValue; + +/** + * A StaticBucketMap is an efficient, thread-safe implementation of + * java.util.Map that performs well in in a highly + * thread-contentious environment. The map supports very efficient + * {@link #get(Object) get}, {@link #put(Object,Object) put}, + * {@link #remove(Object) remove} and {@link #containsKey(Object) containsKey} + * operations, assuming (approximate) uniform hashing and + * that the number of entries does not exceed the number of buckets. If the + * number of entries exceeds the number of buckets or if the hash codes of the + * objects are not uniformly distributed, these operations have a worst case + * scenario that is proportional to the number of elements in the map + * (O(n)).

              + * + * Each bucket in the hash table has its own monitor, so two threads can + * safely operate on the map at the same time, often without incurring any + * monitor contention. This means that you don't have to wrap instances + * of this class with {@link java.util.Collections#synchronizedMap(Map)}; + * instances are already thread-safe. Unfortunately, however, this means + * that this map implementation behaves in ways you may find disconcerting. + * Bulk operations, such as {@link #putAll(Map) putAll} or the + * {@link Collection#retainAll(Collection) retainAll} operation in collection + * views, are not atomic. If two threads are simultaneously + * executing + * + *

              + *   staticBucketMapInstance.putAll(map);
              + * 
              + * + * and + * + *
              + *   staticBucketMapInstance.entrySet().removeAll(map.entrySet());
              + * 
              + * + * then the results are generally random. Those two statement could cancel + * each other out, leaving staticBucketMapInstance essentially + * unchanged, or they could leave some random subset of map in + * staticBucketMapInstance.

              + * + * Also, much like an encyclopedia, the results of {@link #size()} and + * {@link #isEmpty()} are out-of-date as soon as they are produced.

              + * + * The iterators returned by the collection views of this class are not + * fail-fast. They will never raise a + * {@link java.util.ConcurrentModificationException}. Keys and values + * added to the map after the iterator is created do not necessarily appear + * during iteration. Similarly, the iterator does not necessarily fail to + * return keys and values that were removed after the iterator was created.

              + * + * Finally, unlike {@link java.util.HashMap}-style implementations, this + * class never rehashes the map. The number of buckets is fixed + * at construction time and never altered. Performance may degrade if + * you do not allocate enough buckets upfront.

              + * + * The {@link #atomic(Runnable)} method is provided to allow atomic iterations + * and bulk operations; however, overuse of {@link #atomic(Runnable) atomic} + * will basically result in a map that's slower than an ordinary synchronized + * {@link java.util.HashMap}. + * + * Use this class if you do not require reliable bulk operations and + * iterations, or if you can make your own guarantees about how bulk + * operations will affect the map.

              + * + * @since 3.0 (previously in main package v2.1) + * @version $Id: StaticBucketMap.java 1477799 2013-04-30 19:56:11Z tn $ + */ +public final class StaticBucketMap extends AbstractIterableMap { + + /** The default number of buckets to use */ + private static final int DEFAULT_BUCKETS = 255; + /** The array of buckets, where the actual data is held */ + private final Node[] buckets; + /** The matching array of locks */ + private final Lock[] locks; + + /** + * Initializes the map with the default number of buckets (255). + */ + public StaticBucketMap() { + this(DEFAULT_BUCKETS); + } + + /** + * Initializes the map with a specified number of buckets. The number + * of buckets is never below 17, and is always an odd number (StaticBucketMap + * ensures this). The number of buckets is inversely proportional to the + * chances for thread contention. The fewer buckets, the more chances for + * thread contention. The more buckets the fewer chances for thread + * contention. + * + * @param numBuckets the number of buckets for this map + */ + @SuppressWarnings("unchecked") + public StaticBucketMap(final int numBuckets) { + int size = Math.max(17, numBuckets); + + // Ensure that bucketSize is never a power of 2 (to ensure maximal distribution) + if (size % 2 == 0) { + size--; + } + + buckets = new Node[size]; + locks = new Lock[size]; + + for (int i = 0; i < size; i++) { + locks[i] = new Lock(); + } + } + + //----------------------------------------------------------------------- + /** + * Determine the exact hash entry for the key. The hash algorithm + * is rather simplistic, but it does the job: + * + *

              +     *   He = |Hk mod n|
              +     * 
              + * + *

              + * He is the entry's hashCode, Hk is the key's hashCode, and n is + * the number of buckets. + *

              + */ + private int getHash(final Object key) { + if (key == null) { + return 0; + } + int hash = key.hashCode(); + hash += ~(hash << 15); + hash ^= (hash >>> 10); + hash += (hash << 3); + hash ^= (hash >>> 6); + hash += ~(hash << 11); + hash ^= (hash >>> 16); + hash %= buckets.length; + return (hash < 0) ? hash * -1 : hash; + } + + /** + * Gets the current size of the map. + * The value is computed fresh each time the method is called. + * + * @return the current size + */ + public int size() { + int cnt = 0; + + for (int i = 0; i < buckets.length; i++) { + synchronized(locks[i]) { + cnt += locks[i].size; + } + } + return cnt; + } + + /** + * Checks if the size is currently zero. + * + * @return true if empty + */ + public boolean isEmpty() { + return (size() == 0); + } + + /** + * Gets the value associated with the key. + * + * @param key the key to retrieve + * @return the associated value + */ + public V get(final Object key) { + final int hash = getHash(key); + + synchronized (locks[hash]) { + Node n = buckets[hash]; + + while (n != null) { + if (n.key == key || (n.key != null && n.key.equals(key))) { + return n.value; + } + + n = n.next; + } + } + return null; + } + + /** + * Checks if the map contains the specified key. + * + * @param key the key to check + * @return true if found + */ + public boolean containsKey(final Object key) { + final int hash = getHash(key); + + synchronized (locks[hash]) { + Node n = buckets[hash]; + + while (n != null) { + if (n.key == key || (n.key != null && n.key.equals(key))) { + return true; + } + + n = n.next; + } + } + return false; + } + + /** + * Checks if the map contains the specified value. + * + * @param value the value to check + * @return true if found + */ + public boolean containsValue(final Object value) { + for (int i = 0; i < buckets.length; i++) { + synchronized (locks[i]) { + Node n = buckets[i]; + + while (n != null) { + if (n.value == value || (n.value != null && n.value.equals(value))) { + return true; + } + + n = n.next; + } + } + } + return false; + } + + //----------------------------------------------------------------------- + /** + * Puts a new key value mapping into the map. + * + * @param key the key to use + * @param value the value to use + * @return the previous mapping for the key + */ + public V put(final K key, final V value) { + final int hash = getHash(key); + + synchronized (locks[hash]) { + Node n = buckets[hash]; + + if (n == null) { + n = new Node(); + n.key = key; + n.value = value; + buckets[hash] = n; + locks[hash].size++; + return null; + } + + // Set n to the last node in the linked list. Check each key along the way + // If the key is found, then change the value of that node and return + // the old value. + for (Node next = n; next != null; next = next.next) { + n = next; + + if (n.key == key || (n.key != null && n.key.equals(key))) { + final V returnVal = n.value; + n.value = value; + return returnVal; + } + } + + // The key was not found in the current list of nodes, add it to the end + // in a new node. + final Node newNode = new Node(); + newNode.key = key; + newNode.value = value; + n.next = newNode; + locks[hash].size++; + } + return null; + } + + /** + * Removes the specified key from the map. + * + * @param key the key to remove + * @return the previous value at this key + */ + public V remove(final Object key) { + final int hash = getHash(key); + + synchronized (locks[hash]) { + Node n = buckets[hash]; + Node prev = null; + + while (n != null) { + if (n.key == key || (n.key != null && n.key.equals(key))) { + // Remove this node from the linked list of nodes. + if (null == prev) { + // This node was the head, set the next node to be the new head. + buckets[hash] = n.next; + } else { + // Set the next node of the previous node to be the node after this one. + prev.next = n.next; + } + locks[hash].size--; + return n.value; + } + + prev = n; + n = n.next; + } + } + return null; + } + + //----------------------------------------------------------------------- + /** + * Gets the key set. + * + * @return the key set + */ + public Set keySet() { + return new KeySet(); + } + + /** + * Gets the values. + * + * @return the values + */ + public Collection values() { + return new Values(); + } + + /** + * Gets the entry set. + * + * @return the entry set + */ + public Set> entrySet() { + return new EntrySet(); + } + + //----------------------------------------------------------------------- + /** + * Puts all the entries from the specified map into this map. + * This operation is not atomic and may have undesired effects. + * + * @param map the map of entries to add + */ + public void putAll(final Map map) { + for (final Map.Entry entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + /** + * Clears the map of all entries. + */ + public void clear() { + for (int i = 0; i < buckets.length; i++) { + final Lock lock = locks[i]; + synchronized (lock) { + buckets[i] = null; + lock.size = 0; + } + } + } + + /** + * Compares this map to another, as per the Map specification. + * + * @param obj the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map == false) { + return false; + } + final Map other = (Map) obj; + return entrySet().equals(other.entrySet()); + } + + /** + * Gets the hash code, as per the Map specification. + * + * @return the hash code + */ + @Override + public int hashCode() { + int hashCode = 0; + + for (int i = 0; i < buckets.length; i++) { + synchronized (locks[i]) { + Node n = buckets[i]; + + while (n != null) { + hashCode += n.hashCode(); + n = n.next; + } + } + } + return hashCode; + } + + //----------------------------------------------------------------------- + /** + * The Map.Entry for the StaticBucketMap. + */ + private static final class Node implements Map.Entry, KeyValue { + protected K key; + protected V value; + protected Node next; + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + @Override + public int hashCode() { + return ((key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode())); + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Map.Entry == false) { + return false; + } + + final Map.Entry e2 = (Map.Entry) obj; + return ( + (key == null ? e2.getKey() == null : key.equals(e2.getKey())) && + (value == null ? e2.getValue() == null : value.equals(e2.getValue()))); + } + + public V setValue(final V obj) { + final V retVal = value; + value = obj; + return retVal; + } + } + + /** + * The lock object, which also includes a count of the nodes in this lock. + */ + private final static class Lock { + public int size; + } + + //----------------------------------------------------------------------- + private class BaseIterator { + private final ArrayList> current = new ArrayList>(); + private int bucket; + private Map.Entry last; + + public boolean hasNext() { + if (current.size() > 0) { + return true; + } + while (bucket < buckets.length) { + synchronized (locks[bucket]) { + Node n = buckets[bucket]; + while (n != null) { + current.add(n); + n = n.next; + } + bucket++; + if (current.size() > 0) { + return true; + } + } + } + return false; + } + + protected Map.Entry nextEntry() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + last = current.remove(current.size() - 1); + return last; + } + + public void remove() { + if (last == null) { + throw new IllegalStateException(); + } + StaticBucketMap.this.remove(last.getKey()); + last = null; + } + } + + private class EntryIterator extends BaseIterator implements Iterator> { + + public Map.Entry next() { + return nextEntry(); + } + + } + + private class ValueIterator extends BaseIterator implements Iterator { + + public V next() { + return nextEntry().getValue(); + } + + } + + private class KeyIterator extends BaseIterator implements Iterator { + + public K next() { + return nextEntry().getKey(); + } + + } + + private class EntrySet extends AbstractSet> { + + @Override + public int size() { + return StaticBucketMap.this.size(); + } + + @Override + public void clear() { + StaticBucketMap.this.clear(); + } + + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + @Override + public boolean contains(final Object obj) { + final Map.Entry entry = (Map.Entry) obj; + final int hash = getHash(entry.getKey()); + synchronized (locks[hash]) { + for (Node n = buckets[hash]; n != null; n = n.next) { + if (n.equals(entry)) { + return true; + } + } + } + return false; + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + final int hash = getHash(entry.getKey()); + synchronized (locks[hash]) { + for (Node n = buckets[hash]; n != null; n = n.next) { + if (n.equals(entry)) { + StaticBucketMap.this.remove(n.getKey()); + return true; + } + } + } + return false; + } + + } + + private class KeySet extends AbstractSet { + + @Override + public int size() { + return StaticBucketMap.this.size(); + } + + @Override + public void clear() { + StaticBucketMap.this.clear(); + } + + @Override + public Iterator iterator() { + return new KeyIterator(); + } + + @Override + public boolean contains(final Object obj) { + return StaticBucketMap.this.containsKey(obj); + } + + @Override + public boolean remove(final Object obj) { + final int hash = getHash(obj); + synchronized (locks[hash]) { + for (Node n = buckets[hash]; n != null; n = n.next) { + final Object k = n.getKey(); + if ((k == obj) || ((k != null) && k.equals(obj))) { + StaticBucketMap.this.remove(k); + return true; + } + } + } + return false; + } + + } + + + private class Values extends AbstractCollection { + + @Override + public int size() { + return StaticBucketMap.this.size(); + } + + @Override + public void clear() { + StaticBucketMap.this.clear(); + } + + @Override + public Iterator iterator() { + return new ValueIterator(); + } + + } + + /** + * Prevents any operations from occurring on this map while the + * given {@link Runnable} executes. This method can be used, for + * instance, to execute a bulk operation atomically: + * + *
              +     *    staticBucketMapInstance.atomic(new Runnable() {
              +     *        public void run() {
              +     *            staticBucketMapInstance.putAll(map);
              +     *        }
              +     *    });
              +     *  
              + * + * It can also be used if you need a reliable iterator: + * + *
              +     *    staticBucketMapInstance.atomic(new Runnable() {
              +     *        public void run() {
              +     *            Iterator iterator = staticBucketMapInstance.iterator();
              +     *            while (iterator.hasNext()) {
              +     *                foo(iterator.next();
              +     *            }
              +     *        }
              +     *    });
              +     *  
              + * + * Implementation note: This method requires a lot of time + * and a ton of stack space. Essentially a recursive algorithm is used + * to enter each bucket's monitor. If you have twenty thousand buckets + * in your map, then the recursive method will be invoked twenty thousand + * times. You have been warned. + * + * @param r the code to execute atomically + */ + public void atomic(final Runnable r) { + if (r == null) { + throw new NullPointerException(); + } + atomic(r, 0); + } + + private void atomic(final Runnable r, final int bucket) { + if (bucket >= buckets.length) { + r.run(); + return; + } + synchronized (locks[bucket]) { + atomic(r, bucket + 1); + } + } + +} diff --git a/src/org/apache/commons/collections4/map/TransformedMap.java b/src/org/apache/commons/collections4/map/TransformedMap.java new file mode 100644 index 0000000..b016f4c --- /dev/null +++ b/src/org/apache/commons/collections4/map/TransformedMap.java @@ -0,0 +1,246 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another Map to transform objects that are added. + *

              + * The Map put methods and Map.Entry setValue method are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

              + * Note that TransformedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + *

              + * @see org.apache.commons.collections4.splitmap.TransformedSplitMap + * + * @since 3.0 + * @version $Id: TransformedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedMap + extends AbstractInputCheckedMapDecorator + implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 7023152376788900464L; + + /** The transformer to use for the key */ + protected final Transformer keyTransformer; + /** The transformer to use for the value */ + protected final Transformer valueTransformer; + + /** + * Factory method to create a transforming map. + *

              + * If there are any elements already in the map being decorated, they + * are NOT transformed. + * Contrast this with {@link #transformedMap(Map, Transformer, Transformer)}. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param keyTransformer the transformer to use for key conversion, null means no transformation + * @param valueTransformer the transformer to use for value conversion, null means no transformation + * @return a new transformed map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static TransformedMap transformingMap(final Map map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + return new TransformedMap(map, keyTransformer, valueTransformer); + } + + /** + * Factory method to create a transforming map that will transform + * existing contents of the specified map. + *

              + * If there are any elements already in the map being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingMap(Map, Transformer, Transformer)}. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param keyTransformer the transformer to use for key conversion, null means no transformation + * @param valueTransformer the transformer to use for value conversion, null means no transformation + * @return a new transformed map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static TransformedMap transformedMap(final Map map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + final TransformedMap decorated = new TransformedMap(map, keyTransformer, valueTransformer); + if (map.size() > 0) { + final Map transformed = decorated.transformMap(map); + decorated.clear(); + decorated.decorated().putAll(transformed); // avoids double transformation + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the collection being decorated, they + * are NOT transformed. + * + * @param map the map to decorate, must not be null + * @param keyTransformer the transformer to use for key conversion, null means no conversion + * @param valueTransformer the transformer to use for value conversion, null means no conversion + * @throws NullPointerException if map is null + */ + protected TransformedMap(final Map map, final Transformer keyTransformer, + final Transformer valueTransformer) { + super(map); + this.keyTransformer = keyTransformer; + this.valueTransformer = valueTransformer; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + //----------------------------------------------------------------------- + /** + * Transforms a key. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param object the object to transform + * @return the transformed object + */ + protected K transformKey(final K object) { + if (keyTransformer == null) { + return object; + } + return keyTransformer.transform(object); + } + + /** + * Transforms a value. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param object the object to transform + * @return the transformed object + */ + protected V transformValue(final V object) { + if (valueTransformer == null) { + return object; + } + return valueTransformer.transform(object); + } + + /** + * Transforms a map. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param map the map to transform + * @return the transformed object + */ + @SuppressWarnings("unchecked") + protected Map transformMap(final Map map) { + if (map.isEmpty()) { + return (Map) map; + } + final Map result = new LinkedMap(map.size()); + + for (final Map.Entry entry : map.entrySet()) { + result.put(transformKey(entry.getKey()), transformValue(entry.getValue())); + } + return result; + } + + /** + * Override to transform the value when using setValue. + * + * @param value the value to transform + * @return the transformed value + * @since 3.1 + */ + @Override + protected V checkSetValue(final V value) { + return valueTransformer.transform(value); + } + + /** + * Override to only return true when there is a value transformer. + * + * @return true if a value transformer is in use + * @since 3.1 + */ + @Override + protected boolean isSetValueChecking() { + return valueTransformer != null; + } + + //----------------------------------------------------------------------- + @Override + public V put(K key, V value) { + key = transformKey(key); + value = transformValue(value); + return decorated().put(key, value); + } + + @Override + public void putAll(Map mapToCopy) { + mapToCopy = transformMap(mapToCopy); + decorated().putAll(mapToCopy); + } + +} diff --git a/src/org/apache/commons/collections4/map/TransformedSortedMap.java b/src/org/apache/commons/collections4/map/TransformedSortedMap.java new file mode 100644 index 0000000..727f574 --- /dev/null +++ b/src/org/apache/commons/collections4/map/TransformedSortedMap.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.util.Comparator; +import java.util.Map; +import java.util.SortedMap; + +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another SortedMap to transform objects that are added. + *

              + * The Map put methods and Map.Entry setValue method are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

              + * Note that TransformedSortedMap is not synchronized and is not thread-safe. + * If you wish to use this map from multiple threads concurrently, you must use + * appropriate synchronization. The simplest approach is to wrap this map + * using {@link java.util.Collections#synchronizedSortedMap}. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: TransformedSortedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedSortedMap + extends TransformedMap + implements SortedMap { + + /** Serialization version */ + private static final long serialVersionUID = -8751771676410385778L; + + /** + * Factory method to create a transforming sorted map. + *

              + * If there are any elements already in the map being decorated, they are NOT transformed. + * Contrast this with {@link #transformedSortedMap(SortedMap, Transformer, Transformer)}. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param keyTransformer the predicate to validate the keys, null means no transformation + * @param valueTransformer the predicate to validate to values, null means no transformation + * @return a new transformed sorted map + * @throws NullPointerException if the map is null + * @since 4.0 + */ + public static TransformedSortedMap transformingSortedMap(final SortedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + return new TransformedSortedMap(map, keyTransformer, valueTransformer); + } + + /** + * Factory method to create a transforming sorted map that will transform + * existing contents of the specified map. + *

              + * If there are any elements already in the map being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingSortedMap(SortedMap, Transformer, Transformer)}. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @param keyTransformer the transformer to use for key conversion, null means no transformation + * @param valueTransformer the transformer to use for value conversion, null means no transformation + * @return a new transformed sorted map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static TransformedSortedMap transformedSortedMap(final SortedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + + final TransformedSortedMap decorated = + new TransformedSortedMap(map, keyTransformer, valueTransformer); + if (map.size() > 0) { + final Map transformed = decorated.transformMap(map); + decorated.clear(); + decorated.decorated().putAll(transformed); // avoids double transformation + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the collection being decorated, they + * are NOT transformed.

              + * + * @param map the map to decorate, must not be null + * @param keyTransformer the predicate to validate the keys, null means no transformation + * @param valueTransformer the predicate to validate to values, null means no transformation + * @throws NullPointerException if the map is null + */ + protected TransformedSortedMap(final SortedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + super(map, keyTransformer, valueTransformer); + } + + //----------------------------------------------------------------------- + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + protected SortedMap getSortedMap() { + return (SortedMap) map; + } + + //----------------------------------------------------------------------- + public K firstKey() { + return getSortedMap().firstKey(); + } + + public K lastKey() { + return getSortedMap().lastKey(); + } + + public Comparator comparator() { + return getSortedMap().comparator(); + } + + public SortedMap subMap(final K fromKey, final K toKey) { + final SortedMap map = getSortedMap().subMap(fromKey, toKey); + return new TransformedSortedMap(map, keyTransformer, valueTransformer); + } + + public SortedMap headMap(final K toKey) { + final SortedMap map = getSortedMap().headMap(toKey); + return new TransformedSortedMap(map, keyTransformer, valueTransformer); + } + + public SortedMap tailMap(final K fromKey) { + final SortedMap map = getSortedMap().tailMap(fromKey); + return new TransformedSortedMap(map, keyTransformer, valueTransformer); + } + +} diff --git a/src/org/apache/commons/collections4/map/UnmodifiableEntrySet.java b/src/org/apache/commons/collections4/map/UnmodifiableEntrySet.java new file mode 100644 index 0000000..62d2706 --- /dev/null +++ b/src/org/apache/commons/collections4/map/UnmodifiableEntrySet.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; +import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator; +import org.apache.commons.collections4.set.AbstractSetDecorator; + +/** + * Decorates a map entry Set to ensure it can't be altered. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableEntrySet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableEntrySet + extends AbstractSetDecorator> implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = 1678353579659253473L; + + /** + * Factory method to create an unmodifiable set of Map Entry objects. + * + * @param the key type + * @param the value type + * @param set the set to decorate, must not be null + * @return a new unmodifiable entry set + * @throws NullPointerException if set is null + * @since 4.0 + */ + public static Set> unmodifiableEntrySet(final Set> set) { + if (set instanceof Unmodifiable) { + return set; + } + return new UnmodifiableEntrySet(set); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws NullPointerException if set is null + */ + private UnmodifiableEntrySet(final Set> set) { + super(set); + } + + //----------------------------------------------------------------------- + @Override + public boolean add(final Map.Entry object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection> coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public Iterator> iterator() { + return new UnmodifiableEntrySetIterator(decorated().iterator()); + } + + @Override + @SuppressWarnings("unchecked") + public Object[] toArray() { + final Object[] array = decorated().toArray(); + for (int i = 0; i < array.length; i++) { + array[i] = new UnmodifiableEntry((Map.Entry) array[i]); + } + return array; + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(final T[] array) { + Object[] result = array; + if (array.length > 0) { + // we must create a new array to handle multi-threaded situations + // where another thread could access data before we decorate it + result = (Object[]) Array.newInstance(array.getClass().getComponentType(), 0); + } + result = decorated().toArray(result); + for (int i = 0; i < result.length; i++) { + result[i] = new UnmodifiableEntry((Map.Entry) result[i]); + } + + // check to see if result should be returned straight + if (result.length > array.length) { + return (T[]) result; + } + + // copy back into input array to fulfill the method contract + System.arraycopy(result, 0, array, 0, result.length); + if (array.length > result.length) { + array[result.length] = null; + } + return array; + } + + //----------------------------------------------------------------------- + /** + * Implementation of an entry set iterator. + */ + private class UnmodifiableEntrySetIterator extends AbstractIteratorDecorator> { + + protected UnmodifiableEntrySetIterator(final Iterator> iterator) { + super(iterator); + } + + @Override + public Map.Entry next() { + return new UnmodifiableEntry(getIterator().next()); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + //----------------------------------------------------------------------- + /** + * Implementation of a map entry that is unmodifiable. + */ + private class UnmodifiableEntry extends AbstractMapEntryDecorator { + + protected UnmodifiableEntry(final Map.Entry entry) { + super(entry); + } + + @Override + public V setValue(final V obj) { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/src/org/apache/commons/collections4/map/UnmodifiableMap.java b/src/org/apache/commons/collections4/map/UnmodifiableMap.java new file mode 100644 index 0000000..47c72f7 --- /dev/null +++ b/src/org/apache/commons/collections4/map/UnmodifiableMap.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.IterableMap; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.iterators.EntrySetMapIterator; +import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another Map to ensure it can't be altered. + *

              + * This class is Serializable from Commons Collections 3.1. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableMap + extends AbstractMapDecorator + implements Unmodifiable, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 2737023427269031941L; + + /** + * Factory method to create an unmodifiable map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return a new unmodifiable map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static Map unmodifiableMap(final Map map) { + if (map instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final Map tmpMap = (Map) map; + return tmpMap; + } + return new UnmodifiableMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableMap(final Map map) { + super((Map) map); + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); + } + + //----------------------------------------------------------------------- + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(final Map mapToCopy) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public MapIterator mapIterator() { + if (map instanceof IterableMap) { + final MapIterator it = ((IterableMap) map).mapIterator(); + return UnmodifiableMapIterator.unmodifiableMapIterator(it); + } + final MapIterator it = new EntrySetMapIterator(map); + return UnmodifiableMapIterator.unmodifiableMapIterator(it); + } + + @Override + public Set> entrySet() { + final Set> set = super.entrySet(); + return UnmodifiableEntrySet.unmodifiableEntrySet(set); + } + + @Override + public Set keySet() { + final Set set = super.keySet(); + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Collection values() { + final Collection coll = super.values(); + return UnmodifiableCollection.unmodifiableCollection(coll); + } + +} diff --git a/src/org/apache/commons/collections4/map/UnmodifiableOrderedMap.java b/src/org/apache/commons/collections4/map/UnmodifiableOrderedMap.java new file mode 100644 index 0000000..2a29c13 --- /dev/null +++ b/src/org/apache/commons/collections4/map/UnmodifiableOrderedMap.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.iterators.UnmodifiableOrderedMapIterator; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another OrderedMap to ensure it can't be altered. + *

              + * This class is Serializable from Commons Collections 3.1. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableOrderedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableOrderedMap extends AbstractOrderedMapDecorator implements + Unmodifiable, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 8136428161720526266L; + + /** + * Factory method to create an unmodifiable sorted map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return a new ordered map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static OrderedMap unmodifiableOrderedMap(final OrderedMap map) { + if (map instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final OrderedMap tmpMap = (OrderedMap) map; + return tmpMap; + } + return new UnmodifiableOrderedMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableOrderedMap(final OrderedMap map) { + super((OrderedMap) map); + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + //----------------------------------------------------------------------- + @Override + public OrderedMapIterator mapIterator() { + final OrderedMapIterator it = decorated().mapIterator(); + return UnmodifiableOrderedMapIterator.unmodifiableOrderedMapIterator(it); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(final Map mapToCopy) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> entrySet() { + final Set> set = super.entrySet(); + return UnmodifiableEntrySet.unmodifiableEntrySet(set); + } + + @Override + public Set keySet() { + final Set set = super.keySet(); + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Collection values() { + final Collection coll = super.values(); + return UnmodifiableCollection.unmodifiableCollection(coll); + } + +} diff --git a/src/org/apache/commons/collections4/map/UnmodifiableSortedMap.java b/src/org/apache/commons/collections4/map/UnmodifiableSortedMap.java new file mode 100644 index 0000000..62cb270 --- /dev/null +++ b/src/org/apache/commons/collections4/map/UnmodifiableSortedMap.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another SortedMap to ensure it can't be altered. + *

              + * This class is Serializable from Commons Collections 3.1. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableSortedMap.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableSortedMap + extends AbstractSortedMapDecorator + implements Unmodifiable, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 5805344239827376360L; + + /** + * Factory method to create an unmodifiable sorted map. + * + * @param the key type + * @param the value type + * @param map the map to decorate, must not be null + * @return a new unmodifiable sorted map + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static SortedMap unmodifiableSortedMap(final SortedMap map) { + if (map instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final SortedMap tmpMap = (SortedMap) map; + return tmpMap; + } + return new UnmodifiableSortedMap(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableSortedMap(final SortedMap map) { + super((SortedMap) map); + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + * @since 3.1 + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(map); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); + } + + //----------------------------------------------------------------------- + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(final Map mapToCopy) { + throw new UnsupportedOperationException(); + } + + @Override + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public Set> entrySet() { + return UnmodifiableEntrySet.unmodifiableEntrySet(super.entrySet()); + } + + @Override + public Set keySet() { + return UnmodifiableSet.unmodifiableSet(super.keySet()); + } + + @Override + public Collection values() { + return UnmodifiableCollection.unmodifiableCollection(super.values()); + } + + //----------------------------------------------------------------------- + @Override + public K firstKey() { + return decorated().firstKey(); + } + + @Override + public K lastKey() { + return decorated().lastKey(); + } + + @Override + public Comparator comparator() { + return decorated().comparator(); + } + + @Override + public SortedMap subMap(final K fromKey, final K toKey) { + return new UnmodifiableSortedMap(decorated().subMap(fromKey, toKey)); + } + + @Override + public SortedMap headMap(final K toKey) { + return new UnmodifiableSortedMap(decorated().headMap(toKey)); + } + + @Override + public SortedMap tailMap(final K fromKey) { + return new UnmodifiableSortedMap(decorated().tailMap(fromKey)); + } + +} diff --git a/src/org/apache/commons/collections4/map/package-info.java b/src/org/apache/commons/collections4/map/package-info.java new file mode 100644 index 0000000..f9670a0 --- /dev/null +++ b/src/org/apache/commons/collections4/map/package-info.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the {@link java.util.Map Map}, + * {@link org.apache.commons.collections4.IterableMap IterableMap}, + * {@link org.apache.commons.collections4.OrderedMap OrderedMap} and + * {@link java.util.SortedMap SortedMap} interfaces. + * A Map provides a lookup from a key to a value. + * A number of implementations also support the new MapIterator interface that enables + * simple iteration of map keys and values. + *

              + * The following implementations are provided: + *

                + *
              • CaseInsensitiveMap - map that compares keys in a case insensitive way + *
              • CompositeMap - map that combines multiple maps into a single view + *
              • HashedMap - general purpose HashMap replacement supporting MapIterator + *
              • Flat3Map - designed for good performance at size 3 or less + *
              • LinkedMap - a hash map that maintains insertion order, supporting OrderedMapIterator + *
              • LRUMap - a hash map that maintains a maximum size by removing the least recently used entries + *
              • MultiKeyMap - map that provides special methods for using more than one key to access the value + *
              • ReferenceMap - allows the garbage collector to collect keys and values using equals() for comparison + *
              • ReferenceIdentityMap - allows the garbage collector to collect keys and values using == for comparison + *
              • SingletonMap - a fully featured map to hold one key-value pair + *
              • StaticBucketMap - internally synchronized and designed for thread-contentious environments + *
              + *

              + * The following decorators are provided: + *

                + *
              • Unmodifiable - ensures the collection cannot be altered + *
              • Predicated - ensures that only elements that are valid according to a predicate can be added + *
              • Transformed - transforms each element added + *
              • FixedSize - ensures that the size of the map cannot change + *
              • Defaulted - provides default values for non-existing keys + *
              • Lazy - creates objects in the map on demand + *
              • ListOrdered - ensures that insertion order is retained + *
              + * + * @version $Id: package-info.java 1469004 2013-04-17 17:37:03Z tn $ + */ +package org.apache.commons.collections4.map; + diff --git a/src/org/apache/commons/collections4/multimap/AbstractListValuedMap.java b/src/org/apache/commons/collections4/multimap/AbstractListValuedMap.java new file mode 100644 index 0000000..9ac8bb8 --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/AbstractListValuedMap.java @@ -0,0 +1,289 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.ListValuedMap; + +/** + * Abstract implementation of the {@link ListValuedMap} interface to simplify + * the creation of subclass implementations. + *

              + * Subclasses specify a Map implementation to use as the internal storage and + * the List implementation to use as values. + * + * @since 4.1 + * @version $Id: AbstractListValuedMap.java 1715695 2015-11-22 21:11:49Z tn $ + */ +public abstract class AbstractListValuedMap extends AbstractMultiValuedMap + implements ListValuedMap { + + /** + * Constructor needed for subclass serialisation. + */ + protected AbstractListValuedMap() { + super(); + } + + /** + * A constructor that wraps, not copies + * + * @param map the map to wrap, must not be null + * @throws NullPointerException if the map is null + */ + protected AbstractListValuedMap(final Map> map) { + super(map); + } + + // ----------------------------------------------------------------------- + @Override + @SuppressWarnings("unchecked") + protected Map> getMap() { + return (Map>) super.getMap(); + } + + /** + * Creates a new value collection using the provided factory. + * @return a new list + */ + @Override + protected abstract List createCollection(); + + // ----------------------------------------------------------------------- + /** + * Gets the list of values associated with the specified key. This would + * return an empty list in case the mapping is not present + * + * @param key the key to retrieve + * @return the {@code List} of values, will return an empty {@link List} for no mapping + */ + @Override + public List get(final K key) { + return wrappedCollection(key); + } + + @Override + List wrappedCollection(final K key) { + return new WrappedList(key); + } + + /** + * Removes all values associated with the specified key. + *

              + * A subsequent get(Object) would return an empty list. + * + * @param key the key to remove values from + * @return the List of values removed, will return an empty, + * unmodifiable list for no mapping found. + */ + @Override + public List remove(Object key) { + return ListUtils.emptyIfNull(getMap().remove(key)); + } + + // ----------------------------------------------------------------------- + /** + * Wrapped list to handle add and remove on the list returned by get(object) + */ + private class WrappedList extends WrappedCollection implements List { + + public WrappedList(final K key) { + super(key); + } + + @Override + protected List getMapping() { + return getMap().get(key); + } + + @Override + public void add(int index, V value) { + List list = getMapping(); + if (list == null) { + list = createCollection(); + getMap().put(key, list); + } + list.add(index, value); + } + + @Override + public boolean addAll(int index, Collection c) { + List list = getMapping(); + if (list == null) { + list = createCollection(); + boolean changed = list.addAll(index, c); + if (changed) { + getMap().put(key, list); + } + return changed; + } + return list.addAll(index, c); + } + + @Override + public V get(int index) { + final List list = ListUtils.emptyIfNull(getMapping()); + return list.get(index); + } + + @Override + public int indexOf(Object o) { + final List list = ListUtils.emptyIfNull(getMapping()); + return list.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + final List list = ListUtils.emptyIfNull(getMapping()); + return list.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return new ValuesListIterator(key); + } + + @Override + public ListIterator listIterator(int index) { + return new ValuesListIterator(key, index); + } + + @Override + public V remove(int index) { + final List list = ListUtils.emptyIfNull(getMapping()); + V value = list.remove(index); + if (list.isEmpty()) { + AbstractListValuedMap.this.remove(key); + } + return value; + } + + @Override + public V set(int index, V value) { + final List list = ListUtils.emptyIfNull(getMapping()); + return list.set(index, value); + } + + @Override + public List subList(int fromIndex, int toIndex) { + final List list = ListUtils.emptyIfNull(getMapping()); + return list.subList(fromIndex, toIndex); + } + + @Override + public boolean equals(Object other) { + final List list = getMapping(); + if (list == null) { + return Collections.emptyList().equals(other); + } + if (!(other instanceof List)) { + return false; + } + List otherList = (List) other; + return ListUtils.isEqualList(list, otherList); + } + + @Override + public int hashCode() { + final List list = getMapping(); + return ListUtils.hashCodeForList(list); + } + + } + + /** Values ListIterator */ + private class ValuesListIterator implements ListIterator { + + private final K key; + private List values; + private ListIterator iterator; + + public ValuesListIterator(final K key) { + this.key = key; + this.values = ListUtils.emptyIfNull(getMap().get(key)); + this.iterator = values.listIterator(); + } + + public ValuesListIterator(final K key, int index) { + this.key = key; + this.values = ListUtils.emptyIfNull(getMap().get(key)); + this.iterator = values.listIterator(index); + } + + @Override + public void add(V value) { + if (getMap().get(key) == null) { + List list = createCollection(); + getMap().put(key, list); + this.values = list; + this.iterator = list.listIterator(); + } + this.iterator.add(value); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public boolean hasPrevious() { + return iterator.hasPrevious(); + } + + @Override + public V next() { + return iterator.next(); + } + + @Override + public int nextIndex() { + return iterator.nextIndex(); + } + + @Override + public V previous() { + return iterator.previous(); + } + + @Override + public int previousIndex() { + return iterator.previousIndex(); + } + + @Override + public void remove() { + iterator.remove(); + if (values.isEmpty()) { + getMap().remove(key); + } + } + + @Override + public void set(V value) { + iterator.set(value); + } + + } + +} diff --git a/src/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java b/src/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java new file mode 100644 index 0000000..88e66d3 --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java @@ -0,0 +1,945 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.AbstractCollection; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.IteratorUtils; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; +import org.apache.commons.collections4.iterators.EmptyMapIterator; +import org.apache.commons.collections4.iterators.IteratorChain; +import org.apache.commons.collections4.iterators.LazyIteratorChain; +import org.apache.commons.collections4.iterators.TransformIterator; +import org.apache.commons.collections4.keyvalue.AbstractMapEntry; +import org.apache.commons.collections4.keyvalue.UnmodifiableMapEntry; +import org.apache.commons.collections4.multiset.AbstractMultiSet; +import org.apache.commons.collections4.multiset.UnmodifiableMultiSet; + +import java.util.Set; + +/** + * Abstract implementation of the {@link MultiValuedMap} interface to simplify + * the creation of subclass implementations. + *

              + * Subclasses specify a Map implementation to use as the internal storage. + * + * @since 4.1 + * @version $Id: AbstractMultiValuedMap.java 1715697 2015-11-22 21:20:04Z tn $ + */ +public abstract class AbstractMultiValuedMap implements MultiValuedMap { + + /** The values view */ + private transient Collection valuesView; + + /** The EntryValues view */ + private transient EntryValues entryValuesView; + + /** The KeyMultiSet view */ + private transient MultiSet keysMultiSetView; + + /** The AsMap view */ + private transient AsMap asMapView; + + /** The map used to store the data */ + private transient Map> map; + + /** + * Constructor needed for subclass serialisation. + */ + protected AbstractMultiValuedMap() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the map to wrap, must not be null + * @throws NullPointerException if the map is null + */ + @SuppressWarnings("unchecked") + protected AbstractMultiValuedMap(final Map> map) { + if (map == null) { + throw new NullPointerException("Map must not be null."); + } + this.map = (Map>) map; + } + + // ----------------------------------------------------------------------- + /** + * Gets the map being wrapped. + * + * @return the wrapped map + */ + protected Map> getMap() { + return map; + } + + /** + * Sets the map being wrapped. + *

              + * NOTE: this method should only be used during deserialization + * + * @param map the map to wrap + */ + @SuppressWarnings("unchecked") + protected void setMap(Map> map) { + this.map = (Map>) map; + } + + protected abstract Collection createCollection(); + + // ----------------------------------------------------------------------- + @Override + public boolean containsKey(Object key) { + return getMap().containsKey(key); + } + + @Override + public boolean containsValue(final Object value) { + return values().contains(value); + } + + @Override + public boolean containsMapping(Object key, Object value) { + Collection coll = getMap().get(key); + return coll != null && coll.contains(value); + } + + @Override + public Collection> entries() { + return entryValuesView != null ? entryValuesView : (entryValuesView = new EntryValues()); + } + + /** + * Gets the collection of values associated with the specified key. This + * would return an empty collection in case the mapping is not present + * + * @param key the key to retrieve + * @return the {@code Collection} of values, will return an empty {@code Collection} for no mapping + */ + @Override + public Collection get(final K key) { + return wrappedCollection(key); + } + + Collection wrappedCollection(final K key) { + return new WrappedCollection(key); + } + + /** + * Removes all values associated with the specified key. + *

              + * A subsequent get(Object) would return an empty collection. + * + * @param key the key to remove values from + * @return the Collection of values removed, will return an + * empty, unmodifiable collection for no mapping found + */ + @Override + public Collection remove(Object key) { + return CollectionUtils.emptyIfNull(getMap().remove(key)); + } + + /** + * Removes a specific key/value mapping from the multi-valued map. + *

              + * The value is removed from the collection mapped to the specified key. + * Other values attached to that key are unaffected. + *

              + * If the last value for a key is removed, an empty collection would be + * returned from a subsequent {@link #get(Object)}. + * + * @param key the key to remove from + * @param value the value to remove + * @return true if the mapping was removed, false otherwise + */ + @Override + public boolean removeMapping(final Object key, final Object value) { + final Collection coll = getMap().get(key); + if (coll == null) { + return false; + } + boolean changed = coll.remove(value); + if (coll.isEmpty()) { + getMap().remove(key); + } + return changed; + } + + @Override + public boolean isEmpty() { + return getMap().isEmpty(); + } + + @Override + public Set keySet() { + return getMap().keySet(); + } + + /** + * {@inheritDoc} + *

              + * This implementation does not cache the total size + * of the multi-valued map, but rather calculates it by iterating + * over the entries of the underlying map. + */ + @Override + public int size() { + // the total size should be cached to improve performance + // but this requires that all modifications of the multimap + // (including the wrapped collections and entry/value + // collections) are tracked. + int size = 0; + for (final Collection col : getMap().values()) { + size += col.size(); + } + return size; + } + + /** + * Gets a collection containing all the values in the map. + *

              + * Returns a collection containing all the values from all keys. + * + * @return a collection view of the values contained in this map + */ + @Override + public Collection values() { + final Collection vs = valuesView; + return vs != null ? vs : (valuesView = new Values()); + } + + @Override + public void clear() { + getMap().clear(); + } + + /** + * Adds the value to the collection associated with the specified key. + *

              + * Unlike a normal Map the previous value is not replaced. + * Instead the new value is added to the collection stored against the key. + * + * @param key the key to store against + * @param value the value to add to the collection at the key + * @return the value added if the map changed and null if the map did not change + */ + @Override + public boolean put(final K key, final V value) { + Collection coll = getMap().get(key); + if (coll == null) { + coll = createCollection(); + if (coll.add(value)) { + map.put(key, coll); + return true; + } else { + return false; + } + } else { + return coll.add(value); + } + } + + /** + * Copies all of the mappings from the specified map to this map. The effect + * of this call is equivalent to that of calling {@link #put(Object,Object) + * put(k, v)} on this map once for each mapping from key {@code k} to value + * {@code v} in the specified map. The behavior of this operation is + * undefined if the specified map is modified while the operation is in + * progress. + * + * @param map mappings to be stored in this map, may not be null + * @return true if the map changed as a result of this operation + * @throws NullPointerException if map is null + */ + @Override + public boolean putAll(final Map map) { + if (map == null) { + throw new NullPointerException("Map must not be null."); + } + boolean changed = false; + for (Map.Entry entry : map.entrySet()) { + changed |= put(entry.getKey(), entry.getValue()); + } + return changed; + } + + /** + * Copies all of the mappings from the specified MultiValuedMap to this map. + * The effect of this call is equivalent to that of calling + * {@link #put(Object,Object) put(k, v)} on this map once for each mapping + * from key {@code k} to value {@code v} in the specified map. The + * behavior of this operation is undefined if the specified map is modified + * while the operation is in progress. + * + * @param map mappings to be stored in this map, may not be null + * @return true if the map changed as a result of this operation + * @throws NullPointerException if map is null + */ + @Override + public boolean putAll(final MultiValuedMap map) { + if (map == null) { + throw new NullPointerException("Map must not be null."); + } + boolean changed = false; + for (Map.Entry entry : map.entries()) { + changed |= put(entry.getKey(), entry.getValue()); + } + return changed; + } + + /** + * Returns a {@link MultiSet} view of the key mapping contained in this map. + *

              + * Returns a MultiSet of keys with its values count as the count of the MultiSet. + * This multiset is backed by the map, so any changes in the map is reflected here. + * Any method which modifies this multiset like {@code add}, {@code remove}, + * {@link Iterator#remove()} etc throws {@code UnsupportedOperationException}. + * + * @return a bag view of the key mapping contained in this map + */ + @Override + public MultiSet keys() { + if (keysMultiSetView == null) { + keysMultiSetView = UnmodifiableMultiSet.unmodifiableMultiSet(new KeysMultiSet()); + } + return keysMultiSetView; + } + + @Override + public Map> asMap() { + return asMapView != null ? asMapView : (asMapView = new AsMap(map)); + } + + /** + * Adds Iterable values to the collection associated with the specified key. + * + * @param key the key to store against + * @param values the values to add to the collection at the key, may not be null + * @return true if this map changed + * @throws NullPointerException if values is null + */ + @Override + public boolean putAll(final K key, final Iterable values) { + if (values == null) { + throw new NullPointerException("Values must not be null."); + } + + if (values instanceof Collection) { + Collection valueCollection = (Collection) values; + return !valueCollection.isEmpty() && get(key).addAll(valueCollection); + } else { + Iterator it = values.iterator(); + return it.hasNext() && CollectionUtils.addAll(get(key), it); + } + } + + @Override + public MapIterator mapIterator() { + if (size() == 0) { + return EmptyMapIterator.emptyMapIterator(); + } + return new MultiValuedMapIterator(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MultiValuedMap) { + return asMap().equals(((MultiValuedMap) obj).asMap()); + } + return false; + } + + @Override + public int hashCode() { + return getMap().hashCode(); + } + + @Override + public String toString() { + return getMap().toString(); + } + + // ----------------------------------------------------------------------- + + /** + * Wrapped collection to handle add and remove on the collection returned + * by get(object). + *

              + * Currently, the wrapped collection is not cached and has to be retrieved + * from the underlying map. This is safe, but not very efficient and + * should be improved in subsequent releases. For this purpose, the + * scope of this collection is set to package private to simplify later + * refactoring. + */ + class WrappedCollection implements Collection { + + protected final K key; + + public WrappedCollection(final K key) { + this.key = key; + } + + protected Collection getMapping() { + return getMap().get(key); + } + + @Override + public boolean add(V value) { + Collection coll = getMapping(); + if (coll == null) { + coll = createCollection(); + AbstractMultiValuedMap.this.map.put(key, coll); + } + return coll.add(value); + } + + @Override + public boolean addAll(Collection other) { + Collection coll = getMapping(); + if (coll == null) { + coll = createCollection(); + AbstractMultiValuedMap.this.map.put(key, coll); + } + return coll.addAll(other); + } + + @Override + public void clear() { + final Collection coll = getMapping(); + if (coll != null) { + coll.clear(); + AbstractMultiValuedMap.this.remove(key); + } + } + + @Override + @SuppressWarnings("unchecked") + public Iterator iterator() { + final Collection coll = getMapping(); + if (coll == null) { + return IteratorUtils.EMPTY_ITERATOR; + } + return new ValuesIterator(key); + } + + @Override + public int size() { + final Collection coll = getMapping(); + return coll == null ? 0 : coll.size(); + } + + @Override + public boolean contains(Object obj) { + final Collection coll = getMapping(); + return coll == null ? false : coll.contains(obj); + } + + @Override + public boolean containsAll(Collection other) { + final Collection coll = getMapping(); + return coll == null ? false : coll.containsAll(other); + } + + @Override + public boolean isEmpty() { + final Collection coll = getMapping(); + return coll == null ? true : coll.isEmpty(); + } + + @Override + public boolean remove(Object item) { + final Collection coll = getMapping(); + if (coll == null) { + return false; + } + + boolean result = coll.remove(item); + if (coll.isEmpty()) { + AbstractMultiValuedMap.this.remove(key); + } + return result; + } + + @Override + public boolean removeAll(Collection c) { + final Collection coll = getMapping(); + if (coll == null) { + return false; + } + + boolean result = coll.removeAll(c); + if (coll.isEmpty()) { + AbstractMultiValuedMap.this.remove(key); + } + return result; + } + + @Override + public boolean retainAll(Collection c) { + final Collection coll = getMapping(); + if (coll == null) { + return false; + } + + boolean result = coll.retainAll(c); + if (coll.isEmpty()) { + AbstractMultiValuedMap.this.remove(key); + } + return result; + } + + @Override + public Object[] toArray() { + final Collection coll = getMapping(); + if (coll == null) { + return CollectionUtils.EMPTY_COLLECTION.toArray(); + } + return coll.toArray(); + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final Collection coll = getMapping(); + if (coll == null) { + return (T[]) CollectionUtils.EMPTY_COLLECTION.toArray(a); + } + return coll.toArray(a); + } + + @Override + public String toString() { + final Collection coll = getMapping(); + if (coll == null) { + return CollectionUtils.EMPTY_COLLECTION.toString(); + } + return coll.toString(); + } + + } + + /** + * Inner class that provides a MultiSet keys view. + */ + private class KeysMultiSet extends AbstractMultiSet { + + @Override + public boolean contains(Object o) { + return getMap().containsKey(o); + } + + @Override + public boolean isEmpty() { + return getMap().isEmpty(); + } + + @Override + public int size() { + return AbstractMultiValuedMap.this.size(); + } + + @Override + protected int uniqueElements() { + return getMap().size(); + } + + @Override + public int getCount(Object object) { + int count = 0; + Collection col = AbstractMultiValuedMap.this.getMap().get(object); + if (col != null) { + count = col.size(); + } + return count; + } + + @Override + protected Iterator> createEntrySetIterator() { + final MapEntryTransformer transformer = new MapEntryTransformer(); + return IteratorUtils.transformedIterator(map.entrySet().iterator(), transformer); + } + + private final class MapEntryTransformer + implements Transformer>, MultiSet.Entry> { + @Override + public MultiSet.Entry transform(final Map.Entry> mapEntry) { + return new AbstractMultiSet.AbstractEntry() { + @Override + public K getElement() { + return mapEntry.getKey(); + } + + @Override + public int getCount() { + return mapEntry.getValue().size(); + } + }; + } + } + } + + /** + * Inner class that provides the Entry view + */ + private class EntryValues extends AbstractCollection> { + + @Override + public Iterator> iterator() { + return new LazyIteratorChain>() { + + final Collection keysCol = new ArrayList(getMap().keySet()); + final Iterator keyIterator = keysCol.iterator(); + + @Override + protected Iterator> nextIterator(int count) { + if (!keyIterator.hasNext()) { + return null; + } + final K key = keyIterator.next(); + final Transformer> entryTransformer = new Transformer>() { + + @Override + public Entry transform(final V input) { + return new MultiValuedMapEntry(key, input); + } + + }; + return new TransformIterator>(new ValuesIterator(key), entryTransformer); + } + }; + } + + @Override + public int size() { + return AbstractMultiValuedMap.this.size(); + } + + } + + /** + * Inner class for MultiValuedMap Entries. + */ + private class MultiValuedMapEntry extends AbstractMapEntry { + + public MultiValuedMapEntry(K key, V value) { + super(key, value); + } + + @Override + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + + } + + /** + * Inner class for MapIterator. + */ + private class MultiValuedMapIterator implements MapIterator { + + private final Iterator> it; + + private Entry current = null; + + public MultiValuedMapIterator() { + this.it = AbstractMultiValuedMap.this.entries().iterator(); + } + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public K next() { + current = it.next(); + return current.getKey(); + } + + @Override + public K getKey() { + if (current == null) { + throw new IllegalStateException(); + } + return current.getKey(); + } + + @Override + public V getValue() { + if (current == null) { + throw new IllegalStateException(); + } + return current.getValue(); + } + + @Override + public void remove() { + it.remove(); + } + + @Override + public V setValue(V value) { + if (current == null) { + throw new IllegalStateException(); + } + return current.setValue(value); + } + + } + + /** + * Inner class that provides the values view. + */ + private class Values extends AbstractCollection { + @Override + public Iterator iterator() { + final IteratorChain chain = new IteratorChain(); + for (final K k : keySet()) { + chain.addIterator(new ValuesIterator(k)); + } + return chain; + } + + @Override + public int size() { + return AbstractMultiValuedMap.this.size(); + } + + @Override + public void clear() { + AbstractMultiValuedMap.this.clear(); + } + } + + /** + * Inner class that provides the values iterator. + */ + private class ValuesIterator implements Iterator { + private final Object key; + private final Collection values; + private final Iterator iterator; + + public ValuesIterator(final Object key) { + this.key = key; + this.values = getMap().get(key); + this.iterator = values.iterator(); + } + + @Override + public void remove() { + iterator.remove(); + if (values.isEmpty()) { + AbstractMultiValuedMap.this.remove(key); + } + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public V next() { + return iterator.next(); + } + } + + /** + * Inner class that provides the AsMap view. + */ + private class AsMap extends AbstractMap> { + final transient Map> decoratedMap; + + AsMap(final Map> map) { + this.decoratedMap = map; + } + + @Override + public Set>> entrySet() { + return new AsMapEntrySet(); + } + + @Override + public boolean containsKey(Object key) { + return decoratedMap.containsKey(key); + } + + @Override + public Collection get(Object key) { + Collection collection = decoratedMap.get(key); + if (collection == null) { + return null; + } + @SuppressWarnings("unchecked") + K k = (K) key; + return wrappedCollection(k); + } + + @Override + public Set keySet() { + return AbstractMultiValuedMap.this.keySet(); + } + + @Override + public int size() { + return decoratedMap.size(); + } + + @Override + public Collection remove(Object key) { + Collection collection = decoratedMap.remove(key); + if (collection == null) { + return null; + } + + final Collection output = createCollection(); + output.addAll(collection); + collection.clear(); + return output; + } + + @Override + public boolean equals(Object object) { + return this == object || decoratedMap.equals(object); + } + + @Override + public int hashCode() { + return decoratedMap.hashCode(); + } + + @Override + public String toString() { + return decoratedMap.toString(); + } + + @Override + public void clear() { + AbstractMultiValuedMap.this.clear(); + } + + class AsMapEntrySet extends AbstractSet>> { + + @Override + public Iterator>> iterator() { + return new AsMapEntrySetIterator(decoratedMap.entrySet().iterator()); + } + + @Override + public int size() { + return AsMap.this.size(); + } + + @Override + public void clear() { + AsMap.this.clear(); + } + + @Override + public boolean contains(Object o) { + return decoratedMap.entrySet().contains(o); + } + + @Override + public boolean remove(Object o) { + if (!contains(o)) { + return false; + } + Map.Entry entry = (Map.Entry) o; + AbstractMultiValuedMap.this.remove(entry.getKey()); + return true; + } + } + + /** + * EntrySet iterator for the asMap view. + */ + class AsMapEntrySetIterator extends AbstractIteratorDecorator>> { + + AsMapEntrySetIterator(Iterator>> iterator) { + super(iterator); + } + + @Override + public Map.Entry> next() { + final Map.Entry> entry = super.next(); + final K key = entry.getKey(); + return new UnmodifiableMapEntry>(key, wrappedCollection(key)); + } + } + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * @param out the output stream + * @throws IOException any of the usual I/O related exceptions + */ + protected void doWriteObject(final ObjectOutputStream out) throws IOException { + out.writeInt(map.size()); + for (final Map.Entry> entry : map.entrySet()) { + out.writeObject(entry.getKey()); + out.writeInt(entry.getValue().size()); + for (final V value : entry.getValue()) { + out.writeObject(value); + } + } + } + + /** + * Read the map in using a custom routine. + * @param in the input stream + * @throws IOException any of the usual I/O related exceptions + * @throws ClassNotFoundException if the stream contains an object which class can not be loaded + * @throws ClassCastException if the stream does not contain the correct objects + */ + protected void doReadObject(final ObjectInputStream in) + throws IOException, ClassNotFoundException { + final int entrySize = in.readInt(); + for (int i = 0; i < entrySize; i++) { + @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect + final K key = (K) in.readObject(); + final Collection values = get(key); + final int valueSize = in.readInt(); + for (int j = 0; j < valueSize; j++) { + @SuppressWarnings("unchecked") // see above + V value = (V) in.readObject(); + values.add(value); + } + } + } + +} diff --git a/src/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java b/src/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java new file mode 100644 index 0000000..868c21e --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.MultiValuedMap; + +import java.util.Set; + +/** + * Decorates another MultiValuedMap to provide additional behaviour. + *

              + * Each method call made on this MultiValuedMap is forwarded to the + * decorated MultiValuedMap. This class is used as a framework to build + * to extensions such as synchronized and unmodifiable behaviour. + * + * @param the type of key elements + * @param the type of value elements + * + * @since 4.1 + * @version $Id: AbstractMultiValuedMapDecorator.java 1715302 2015-11-19 23:08:01Z tn $ + */ +public abstract class AbstractMultiValuedMapDecorator + implements MultiValuedMap, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 20150612L; + + /** MultiValuedMap to decorate */ + private final MultiValuedMap map; + + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @throws NullPointerException if the map is null + */ + protected AbstractMultiValuedMapDecorator(final MultiValuedMap map) { + if (map == null) { + throw new NullPointerException("MultiValuedMap must not be null."); + } + this.map = map; + } + + // ----------------------------------------------------------------------- + /** + * The decorated multi-valued map. + * + * @return the map to decorate + */ + protected MultiValuedMap decorated() { + return map; + } + + // ----------------------------------------------------------------------- + @Override + public int size() { + return decorated().size(); + } + + @Override + public boolean isEmpty() { + return decorated().isEmpty(); + } + + @Override + public boolean containsKey(final Object key) { + return decorated().containsKey(key); + } + + @Override + public boolean containsValue(final Object value) { + return decorated().containsValue(value); + } + + @Override + public boolean containsMapping(final Object key, final Object value) { + return decorated().containsMapping(key, value); + } + + @Override + public Collection get(final K key) { + return decorated().get(key); + } + + @Override + public Collection remove(final Object key) { + return decorated().remove(key); + } + + @Override + public boolean removeMapping(final Object key, final Object item) { + return decorated().removeMapping(key, item); + } + + @Override + public void clear() { + decorated().clear(); + } + + @Override + public boolean put(K key, V value) { + return decorated().put(key, value); + } + + @Override + public Set keySet() { + return decorated().keySet(); + } + + @Override + public Collection> entries() { + return decorated().entries(); + } + + @Override + public MultiSet keys() { + return decorated().keys(); + } + + @Override + public Collection values() { + return decorated().values(); + } + + @Override + public Map> asMap() { + return decorated().asMap(); + } + + @Override + public boolean putAll(K key, Iterable values) { + return decorated().putAll(key, values); + } + + @Override + public boolean putAll(Map map) { + return decorated().putAll(map); + } + + @Override + public boolean putAll(MultiValuedMap map) { + return decorated().putAll(map); + } + + @Override + public MapIterator mapIterator() { + return decorated().mapIterator(); + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + return decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + @Override + public String toString() { + return decorated().toString(); + } + +} diff --git a/src/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java b/src/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java new file mode 100644 index 0000000..c13579d --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.SetUtils; +import org.apache.commons.collections4.SetValuedMap; + +/** + * Abstract implementation of the {@link SetValuedMap} interface to simplify the + * creation of subclass implementations. + *

              + * Subclasses specify a Map implementation to use as the internal storage and + * the Set implementation to use as values. + * + * @since 4.1 + * @version $Id: AbstractSetValuedMap.java 1715695 2015-11-22 21:11:49Z tn $ + */ +public abstract class AbstractSetValuedMap extends AbstractMultiValuedMap + implements SetValuedMap { + + /** + * Constructor needed for subclass serialisation. + */ + protected AbstractSetValuedMap() { + super(); + } + + /** + * A constructor that wraps, not copies + * + * @param map the map to wrap, must not be null + * @throws NullPointerException if the map is null + */ + protected AbstractSetValuedMap(Map> map) { + super(map); + } + + // ----------------------------------------------------------------------- + @Override + @SuppressWarnings("unchecked") + protected Map> getMap() { + return (Map>) super.getMap(); + } + + /** + * Creates a new value collection using the provided factory. + * @return a new list + */ + @Override + protected abstract Set createCollection(); + + // ----------------------------------------------------------------------- + /** + * Gets the set of values associated with the specified key. This would + * return an empty set in case the mapping is not present + * + * @param key the key to retrieve + * @return the Set of values, will return an empty + * Set for no mapping + */ + @Override + public Set get(final K key) { + return wrappedCollection(key); + } + + @Override + Set wrappedCollection(final K key) { + return new WrappedSet(key); + } + + /** + * Removes all values associated with the specified key. + *

              + * A subsequent get(Object) would return an empty set. + * + * @param key the key to remove values from + * @return the Set of values removed, will return an empty, + * unmodifiable set for no mapping found. + */ + @Override + public Set remove(Object key) { + return SetUtils.emptyIfNull(getMap().remove(key)); + } + + // ----------------------------------------------------------------------- + /** + * Wrapped set to handle add and remove on the collection returned by + * {@code get(Object)}. + */ + private class WrappedSet extends WrappedCollection implements Set { + + public WrappedSet(final K key) { + super(key); + } + + @Override + public boolean equals(Object other) { + final Set set = (Set) getMapping(); + if (set == null) { + return Collections.emptySet().equals(other); + } + if (!(other instanceof Set)) { + return false; + } + Set otherSet = (Set) other; + return SetUtils.isEqualSet(set, otherSet); + } + + @Override + public int hashCode() { + final Set set = (Set) getMapping(); + return SetUtils.hashCodeForSet(set); + } + + } + +} diff --git a/src/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java b/src/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java new file mode 100644 index 0000000..4c645cc --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.collections4.MultiValuedMap; + +/** + * Implements a {@code ListValuedMap}, using a {@link HashMap} to provide data + * storage and {@link ArrayList}s as value collections. This is the standard + * implementation of a ListValuedMap. + *

              + * Note that ArrayListValuedHashMap is not synchronized and is not + * thread-safe. If you wish to use this map from multiple threads + * concurrently, you must use appropriate synchronization. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 4.1 + * @version $Id: ArrayListValuedHashMap.java 1715492 2015-11-21 10:09:31Z tn $ + */ +public class ArrayListValuedHashMap extends AbstractListValuedMap + implements Serializable { + + /** Serialization Version */ + private static final long serialVersionUID = 20151118L; + + /** + * The initial map capacity used when none specified in constructor. + */ + private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16; + + /** + * The initial list capacity when using none specified in constructor. + */ + private static final int DEFAULT_INITIAL_LIST_CAPACITY = 3; + + /** + * The initial list capacity when creating a new value collection. + */ + private final int initialListCapacity; + + /** + * Creates an empty ArrayListValuedHashMap with the default initial + * map capacity (16) and the default initial list capacity (3). + */ + public ArrayListValuedHashMap() { + this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_LIST_CAPACITY); + } + + /** + * Creates an empty ArrayListValuedHashMap with the default initial + * map capacity (16) and the specified initial list capacity. + * + * @param initialListCapacity the initial capacity used for value collections + */ + public ArrayListValuedHashMap(int initialListCapacity) { + this(DEFAULT_INITIAL_MAP_CAPACITY, initialListCapacity); + } + + /** + * Creates an empty ArrayListValuedHashMap with the specified initial + * map and list capacities. + * + * @param initialMapCapacity the initial hashmap capacity + * @param initialListCapacity the initial capacity used for value collections + */ + public ArrayListValuedHashMap(int initialMapCapacity, int initialListCapacity) { + super(new HashMap>(initialMapCapacity)); + this.initialListCapacity = initialListCapacity; + } + + /** + * Creates an ArrayListValuedHashMap copying all the mappings of the given map. + * + * @param map a MultiValuedMap to copy into this map + */ + public ArrayListValuedHashMap(final MultiValuedMap map) { + this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY); + super.putAll(map); + } + + /** + * Creates an ArrayListValuedHashMap copying all the mappings of the given map. + * + * @param map a Map to copy into this map + */ + public ArrayListValuedHashMap(final Map map) { + this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY); + super.putAll(map); + } + + // ----------------------------------------------------------------------- + @Override + protected ArrayList createCollection() { + return new ArrayList(initialListCapacity); + } + + // ----------------------------------------------------------------------- + /** + * Trims the capacity of all value collections to their current size. + */ + public void trimToSize() { + for (Collection coll : getMap().values()) { + final ArrayList list = (ArrayList) coll; + list.trimToSize(); + } + } + + // ----------------------------------------------------------------------- + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + doWriteObject(oos); + } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + setMap(new HashMap>()); + doReadObject(ois); + } + +} diff --git a/src/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java b/src/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java new file mode 100644 index 0000000..3a9396f --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import org.apache.commons.collections4.MultiValuedMap; + +/** + * Implements a {@code SetValuedMap}, using a {@link HashMap} to provide data + * storage and {@link HashSet}s as value collections. This is the standard + * implementation of a SetValuedMap. + *

              + * Note that HashSetValuedHashMap is not synchronized and is not + * thread-safe. If you wish to use this map from multiple threads + * concurrently, you must use appropriate synchronization. This class may throw + * exceptions when accessed by concurrent threads without synchronization. + * + * @since 4.1 + * @version $Id: HashSetValuedHashMap.java 1715492 2015-11-21 10:09:31Z tn $ + */ +public class HashSetValuedHashMap extends AbstractSetValuedMap + implements Serializable { + + /** Serialization Version */ + private static final long serialVersionUID = 20151118L; + + /** + * The initial map capacity used when none specified in constructor. + */ + private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16; + + /** + * The initial set capacity when using none specified in constructor. + */ + private static final int DEFAULT_INITIAL_SET_CAPACITY = 3; + + /** + * The initial list capacity when creating a new value collection. + */ + private final int initialSetCapacity; + + /** + * Creates an empty HashSetValuedHashMap with the default initial + * map capacity (16) and the default initial set capacity (3). + */ + public HashSetValuedHashMap() { + this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_SET_CAPACITY); + } + + /** + * Creates an empty HashSetValuedHashMap with the default initial + * map capacity (16) and the specified initial set capacity. + * + * @param initialSetCapacity the initial capacity used for value collections + */ + public HashSetValuedHashMap(int initialSetCapacity) { + this(DEFAULT_INITIAL_MAP_CAPACITY, initialSetCapacity); + } + + /** + * Creates an empty HashSetValuedHashMap with the specified initial + * map and list capacities. + * + * @param initialMapCapacity the initial hashmap capacity + * @param initialSetCapacity the initial capacity used for value collections + */ + public HashSetValuedHashMap(int initialMapCapacity, int initialSetCapacity) { + super(new HashMap>(initialMapCapacity)); + this.initialSetCapacity = initialSetCapacity; + } + + /** + * Creates an HashSetValuedHashMap copying all the mappings of the given map. + * + * @param map a MultiValuedMap to copy into this map + */ + public HashSetValuedHashMap(final MultiValuedMap map) { + this(map.size(), DEFAULT_INITIAL_SET_CAPACITY); + super.putAll(map); + } + + /** + * Creates an HashSetValuedHashMap copying all the mappings of the given map. + * + * @param map a Map to copy into this map + */ + public HashSetValuedHashMap(final Map map) { + this(map.size(), DEFAULT_INITIAL_SET_CAPACITY); + super.putAll(map); + } + + // ----------------------------------------------------------------------- + @Override + protected HashSet createCollection() { + return new HashSet(initialSetCapacity); + } + + // ----------------------------------------------------------------------- + private void writeObject(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + doWriteObject(oos); + } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + setMap(new HashMap>()); + doReadObject(ois); + } + +} diff --git a/src/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java b/src/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java new file mode 100644 index 0000000..f4131f0 --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.FluentIterable; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another MultiValuedMap to transform objects that are added. + *

              + * This class affects the MultiValuedMap put methods. Thus objects must be + * removed or searched for using their transformed form. For example, if the + * transformation converts Strings to Integers, you must use the Integer form to + * remove objects. + *

              + * Note that TransformedMultiValuedMap is not synchronized and is not thread-safe. + * + * @since 4.1 + * @version $Id: TransformedMultiValuedMap.java 1715302 2015-11-19 23:08:01Z tn $ + */ +public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecorator { + + /** Serialization Version */ + private static final long serialVersionUID = 20150612L; + + /** The key transformer */ + private final Transformer keyTransformer; + + /** The value transformer */ + private final Transformer valueTransformer; + + /** + * Factory method to create a transforming MultiValuedMap. + *

              + * If there are any elements already in the map being decorated, they are + * NOT transformed. Contrast this with + * {@link #transformedMap(MultiValuedMap, Transformer, Transformer)}. + * + * @param the key type + * @param the value type + * @param map the MultiValuedMap to decorate, may not be null + * @param keyTransformer the transformer to use for key conversion, null means no conversion + * @param valueTransformer the transformer to use for value conversion, null means no conversion + * @return a new transformed MultiValuedMap + * @throws NullPointerException if map is null + */ + public static TransformedMultiValuedMap transformingMap(final MultiValuedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + return new TransformedMultiValuedMap(map, keyTransformer, valueTransformer); + } + + /** + * Factory method to create a transforming MultiValuedMap that will + * transform existing contents of the specified map. + *

              + * If there are any elements already in the map being decorated, they will + * be transformed by this method. Contrast this with + * {@link #transformingMap(MultiValuedMap, Transformer, Transformer)}. + * + * @param the key type + * @param the value type + * @param map the MultiValuedMap to decorate, may not be null + * @param keyTransformer the transformer to use for key conversion, null means no conversion + * @param valueTransformer the transformer to use for value conversion, null means no conversion + * @return a new transformed MultiValuedMap + * @throws NullPointerException if map is null + */ + public static TransformedMultiValuedMap transformedMap(final MultiValuedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + final TransformedMultiValuedMap decorated = + new TransformedMultiValuedMap(map, keyTransformer, valueTransformer); + if (!map.isEmpty()) { + final MultiValuedMap mapCopy = new ArrayListValuedHashMap(map); + decorated.clear(); + decorated.putAll(mapCopy); + } + return decorated; + } + + // ----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the collection being decorated, they + * are NOT transformed. + * + * @param map the MultiValuedMap to decorate, may not be null + * @param keyTransformer the transformer to use for key conversion, null means no conversion + * @param valueTransformer the transformer to use for value conversion, null means no conversion + * @throws NullPointerException if map is null + */ + protected TransformedMultiValuedMap(final MultiValuedMap map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + super(map); + this.keyTransformer = keyTransformer; + this.valueTransformer = valueTransformer; + } + + /** + * Transforms a key. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param object the object to transform + * @return the transformed object + */ + protected K transformKey(final K object) { + if (keyTransformer == null) { + return object; + } + return keyTransformer.transform(object); + } + + /** + * Transforms a value. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param object the object to transform + * @return the transformed object + */ + protected V transformValue(final V object) { + if (valueTransformer == null) { + return object; + } + return valueTransformer.transform(object); + } + + @Override + public boolean put(final K key, final V value) { + return decorated().put(transformKey(key), transformValue(value)); + } + + @Override + public boolean putAll(final K key, final Iterable values) { + if (values == null) { + throw new NullPointerException("Values must not be null."); + } + + final Iterable transformedValues = FluentIterable.of(values).transform(valueTransformer); + final Iterator it = transformedValues.iterator(); + return it.hasNext() && CollectionUtils.addAll(decorated().get(transformKey(key)), it); + } + + @Override + public boolean putAll(final Map map) { + if (map == null) { + throw new NullPointerException("Map must not be null."); + } + boolean changed = false; + for (Map.Entry entry : map.entrySet()) { + changed |= put(entry.getKey(), entry.getValue()); + } + return changed; + } + + @Override + public boolean putAll(final MultiValuedMap map) { + if (map == null) { + throw new NullPointerException("Map must not be null."); + } + boolean changed = false; + for (Map.Entry entry : map.entries()) { + changed |= put(entry.getKey(), entry.getValue()); + } + return changed; + } + +} diff --git a/src/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java b/src/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java new file mode 100644 index 0000000..1dc76bb --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multimap; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.collection.UnmodifiableCollection; +import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; +import org.apache.commons.collections4.map.UnmodifiableMap; +import org.apache.commons.collections4.multiset.UnmodifiableMultiSet; +import org.apache.commons.collections4.set.UnmodifiableSet; + +import java.util.Set; + +/** + * Decorates another {@link MultiValuedMap} to ensure it can't be altered. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @param the type of key elements + * @param the type of value elements + * + * @since 4.1 + * @version $Id: UnmodifiableMultiValuedMap.java 1685299 2015-06-13 18:27:11Z tn $ + */ +public final class UnmodifiableMultiValuedMap + extends AbstractMultiValuedMapDecorator implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = 20150612L; + + /** + * Factory method to create an unmodifiable MultiValuedMap. + *

              + * If the map passed in is already unmodifiable, it is returned. + * + * @param the type of key elements + * @param the type of value elements + * @param map the map to decorate, may not be null + * @return an unmodifiable MultiValuedMap + * @throws NullPointerException if map is null + */ + @SuppressWarnings("unchecked") + public static UnmodifiableMultiValuedMap unmodifiableMultiValuedMap( + MultiValuedMap map) { + if (map instanceof Unmodifiable) { + return (UnmodifiableMultiValuedMap) map; + } + return new UnmodifiableMultiValuedMap(map); + } + + /** + * Constructor that wraps (not copies). + * + * @param map the MultiValuedMap to decorate, may not be null + * @throws NullPointerException if the map is null + */ + @SuppressWarnings("unchecked") + private UnmodifiableMultiValuedMap(final MultiValuedMap map) { + super((MultiValuedMap) map); + } + + @Override + public Collection remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeMapping(final Object key, final Object item) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection get(final K key) { + return UnmodifiableCollection.unmodifiableCollection(decorated().get(key)); + } + + @Override + public boolean put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + @Override + public Set keySet() { + return UnmodifiableSet.unmodifiableSet(decorated().keySet()); + } + + @Override + public Collection> entries() { + return UnmodifiableCollection.unmodifiableCollection(decorated().entries()); + } + + @Override + public MultiSet keys() { + return UnmodifiableMultiSet.unmodifiableMultiSet(decorated().keys()); + } + + @Override + public Collection values() { + return UnmodifiableCollection.unmodifiableCollection(decorated().values()); + } + + @Override + public Map> asMap() { + return UnmodifiableMap.unmodifiableMap(decorated().asMap()); + } + + @Override + public MapIterator mapIterator() { + return UnmodifiableMapIterator.unmodifiableMapIterator(decorated().mapIterator()); + } + + @Override + public boolean putAll(final K key, final Iterable values) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean putAll(final Map map) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean putAll(final MultiValuedMap map) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/org/apache/commons/collections4/multimap/package-info.java b/src/org/apache/commons/collections4/multimap/package-info.java new file mode 100644 index 0000000..ee2a4fd --- /dev/null +++ b/src/org/apache/commons/collections4/multimap/package-info.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the {@link org.apache.commons.collections4.MultiValuedMap} interfaces. + * A MultiValuedMap holds a collection of values against each key. + *

              + * The following implementations are provided in the package: + *

                + *
              • ArrayListValuedHashMap - ListValuedMap implementation using a HashMap/ArrayList + *
              • HashSetValuedHashMap - SetValuedMap implementation using a HashMap/HashSet + *
              + *

              + * The following decorators are provided in the package: + *

                + *
              • Transformed - transforms elements added to the MultiValuedMap + *
              • Unmodifiable - ensures the collection cannot be altered + *
              + * + * @version $Id: package-info.java 1715302 2015-11-19 23:08:01Z tn $ + */ +package org.apache.commons.collections4.multimap; diff --git a/src/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java b/src/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java new file mode 100644 index 0000000..0b39f06 --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java @@ -0,0 +1,564 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multiset; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Array; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; + +/** + * Abstract implementation of the {@link MultiSet} interface to simplify the + * creation of subclass implementations. + *

              + * Subclasses specify a Map implementation to use as the internal storage. The + * map will be used to map multiset elements to a number; the number represents the + * number of occurrences of that element in the multiset. + * + * @since 4.1 + * @version $Id: AbstractMapMultiSet.java 1715563 2015-11-21 20:13:35Z tn $ + */ +public abstract class AbstractMapMultiSet extends AbstractMultiSet { + + /** The map to use to store the data */ + private transient Map map; + /** The current total size of the multiset */ + private transient int size; + /** The modification count for fail fast iterators */ + private transient int modCount; + + /** + * Constructor needed for subclass serialisation. + */ + protected AbstractMapMultiSet() { + super(); + } + + /** + * Constructor that assigns the specified Map as the backing store. The map + * must be empty and non-null. + * + * @param map the map to assign + */ + protected AbstractMapMultiSet(final Map map) { + super(); + this.map = map; + } + + /** + * Utility method for implementations to access the map that backs this multiset. + * Not intended for interactive use outside of subclasses. + * + * @return the map being used by the MultiSet + */ + protected Map getMap() { + return map; + } + + /** + * Sets the map being wrapped. + *

              + * NOTE: this method should only be used during deserialization + * + * @param map the map to wrap + */ + protected void setMap(Map map) { + this.map = map; + } + + //----------------------------------------------------------------------- + /** + * Returns the number of elements in this multiset. + * + * @return current size of the multiset + */ + @Override + public int size() { + return size; + } + + /** + * Returns true if the underlying map is empty. + * + * @return true if multiset is empty + */ + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Returns the number of occurrence of the given element in this multiset by + * looking up its count in the underlying map. + * + * @param object the object to search for + * @return the number of occurrences of the object, zero if not found + */ + @Override + public int getCount(final Object object) { + final MutableInteger count = map.get(object); + if (count != null) { + return count.value; + } + return 0; + } + + //----------------------------------------------------------------------- + /** + * Determines if the multiset contains the given element by checking if the + * underlying map contains the element as a key. + * + * @param object the object to search for + * @return true if the multiset contains the given element + */ + @Override + public boolean contains(final Object object) { + return map.containsKey(object); + } + + //----------------------------------------------------------------------- + /** + * Gets an iterator over the multiset elements. Elements present in the + * MultiSet more than once will be returned repeatedly. + * + * @return the iterator + */ + @Override + public Iterator iterator() { + return new MapBasedMultiSetIterator(this); + } + + /** + * Inner class iterator for the MultiSet. + */ + private static class MapBasedMultiSetIterator implements Iterator { + private final AbstractMapMultiSet parent; + private final Iterator> entryIterator; + private Map.Entry current; + private int itemCount; + private final int mods; + private boolean canRemove; + + /** + * Constructor. + * + * @param parent the parent multiset + */ + public MapBasedMultiSetIterator(final AbstractMapMultiSet parent) { + this.parent = parent; + this.entryIterator = parent.map.entrySet().iterator(); + this.current = null; + this.mods = parent.modCount; + this.canRemove = false; + } + + /** {@inheritDoc} */ + @Override + public boolean hasNext() { + return itemCount > 0 || entryIterator.hasNext(); + } + + /** {@inheritDoc} */ + @Override + public E next() { + if (parent.modCount != mods) { + throw new ConcurrentModificationException(); + } + if (itemCount == 0) { + current = entryIterator.next(); + itemCount = current.getValue().value; + } + canRemove = true; + itemCount--; + return current.getKey(); + } + + /** {@inheritDoc} */ + @Override + public void remove() { + if (parent.modCount != mods) { + throw new ConcurrentModificationException(); + } + if (canRemove == false) { + throw new IllegalStateException(); + } + final MutableInteger mut = current.getValue(); + if (mut.value > 1) { + mut.value--; + } else { + entryIterator.remove(); + } + parent.size--; + canRemove = false; + } + } + + //----------------------------------------------------------------------- + @Override + public int add(final E object, final int occurrences) { + if (occurrences < 0) { + throw new IllegalArgumentException("Occurrences must not be negative."); + } + + final MutableInteger mut = map.get(object); + int oldCount = mut != null ? mut.value : 0; + + if (occurrences > 0) { + modCount++; + size += occurrences; + if (mut == null) { + map.put(object, new MutableInteger(occurrences)); + } else { + mut.value += occurrences; + } + } + return oldCount; + } + + //----------------------------------------------------------------------- + /** + * Clears the multiset by clearing the underlying map. + */ + @Override + public void clear() { + modCount++; + map.clear(); + size = 0; + } + + @Override + public int remove(final Object object, final int occurrences) { + if (occurrences < 0) { + throw new IllegalArgumentException("Occurrences must not be negative."); + } + + final MutableInteger mut = map.get(object); + if (mut == null) { + return 0; + } + int oldCount = mut.value; + if (occurrences > 0) { + modCount++; + if (occurrences < mut.value) { + mut.value -= occurrences; + size -= occurrences; + } else { + map.remove(object); + size -= mut.value; + } + } + return oldCount; + } + + //----------------------------------------------------------------------- + /** + * Mutable integer class for storing the data. + */ + protected static class MutableInteger { + /** The value of this mutable. */ + protected int value; + + /** + * Constructor. + * @param value the initial value + */ + MutableInteger(final int value) { + this.value = value; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableInteger == false) { + return false; + } + return ((MutableInteger) obj).value == value; + } + + @Override + public int hashCode() { + return value; + } + } + + //----------------------------------------------------------------------- + @Override + protected Iterator createUniqueSetIterator() { + return new UniqueSetIterator(getMap().keySet().iterator(), this); + } + + @Override + protected int uniqueElements() { + return map.size(); + } + + @Override + protected Iterator> createEntrySetIterator() { + return new EntrySetIterator(map.entrySet().iterator(), this); + } + + //----------------------------------------------------------------------- + /** + * Inner class UniqueSetIterator. + */ + protected static class UniqueSetIterator extends AbstractIteratorDecorator { + + /** The parent multiset */ + protected final AbstractMapMultiSet parent; + + /** The last returned element */ + protected E lastElement = null; + + /** Whether remove is allowed at present */ + protected boolean canRemove = false; + + /** + * Constructor. + * @param iterator the iterator to decorate + * @param parent the parent multiset + */ + protected UniqueSetIterator(final Iterator iterator, final AbstractMapMultiSet parent) { + super(iterator); + this.parent = parent; + } + + @Override + public E next() { + lastElement = super.next(); + canRemove = true; + return lastElement; + } + + @Override + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + final int count = parent.getCount(lastElement); + super.remove(); + parent.remove(lastElement, count); + lastElement = null; + canRemove = false; + } + } + + /** + * Inner class EntrySetIterator. + */ + protected static class EntrySetIterator implements Iterator> { + + /** The parent map */ + protected final AbstractMapMultiSet parent; + + protected final Iterator> decorated; + + /** The last returned entry */ + protected Entry last = null; + + /** Whether remove is allowed at present */ + protected boolean canRemove = false; + + /** + * Constructor. + * @param iterator the iterator to decorate + * @param parent the parent multiset + */ + protected EntrySetIterator(final Iterator> iterator, + final AbstractMapMultiSet parent) { + this.decorated = iterator; + this.parent = parent; + } + + @Override + public boolean hasNext() { + return decorated.hasNext(); + } + + @Override + public Entry next() { + last = new MultiSetEntry(decorated.next()); + canRemove = true; + return last; + } + + @Override + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + decorated.remove(); + last = null; + canRemove = false; + } + } + + /** + * Inner class MultiSetEntry. + */ + protected static class MultiSetEntry extends AbstractEntry { + + protected final Map.Entry parentEntry; + + /** + * Constructor. + * @param parentEntry the entry to decorate + */ + protected MultiSetEntry(final Map.Entry parentEntry) { + this.parentEntry = parentEntry; + } + + @Override + public E getElement() { + return parentEntry.getKey(); + } + + @Override + public int getCount() { + return parentEntry.getValue().value; + } + } + + //----------------------------------------------------------------------- + /** + * Write the multiset out using a custom routine. + * @param out the output stream + * @throws IOException any of the usual I/O related exceptions + */ + @Override + protected void doWriteObject(final ObjectOutputStream out) throws IOException { + out.writeInt(map.size()); + for (final Map.Entry entry : map.entrySet()) { + out.writeObject(entry.getKey()); + out.writeInt(entry.getValue().value); + } + } + + /** + * Read the multiset in using a custom routine. + * @param in the input stream + * @throws IOException any of the usual I/O related exceptions + * @throws ClassNotFoundException if the stream contains an object which class can not be loaded + * @throws ClassCastException if the stream does not contain the correct objects + */ + @Override + protected void doReadObject(final ObjectInputStream in) + throws IOException, ClassNotFoundException { + final int entrySize = in.readInt(); + for (int i = 0; i < entrySize; i++) { + @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect + final E obj = (E) in.readObject(); + final int count = in.readInt(); + map.put(obj, new MutableInteger(count)); + size += count; + } + } + + //----------------------------------------------------------------------- + /** + * Returns an array of all of this multiset's elements. + * + * @return an array of all of this multiset's elements + */ + @Override + public Object[] toArray() { + final Object[] result = new Object[size()]; + int i = 0; + for (final Map.Entry entry : map.entrySet()) { + final E current = entry.getKey(); + final MutableInteger count = entry.getValue(); + for (int index = count.value; index > 0; index--) { + result[i++] = current; + } + } + return result; + } + + /** + * Returns an array of all of this multiset's elements. + * If the input array has more elements than are in the multiset, + * trailing elements will be set to null. + * + * @param the type of the array elements + * @param array the array to populate + * @return an array of all of this multiset's elements + * @throws ArrayStoreException if the runtime type of the specified array is not + * a supertype of the runtime type of the elements in this list + * @throws NullPointerException if the specified array is null + */ + @Override + public T[] toArray(T[] array) { + final int size = size(); + if (array.length < size) { + @SuppressWarnings("unchecked") // safe as both are of type T + final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size); + array = unchecked; + } + + int i = 0; + for (final Map.Entry entry : map.entrySet()) { + final E current = entry.getKey(); + final MutableInteger count = entry.getValue(); + for (int index = count.value; index > 0; index--) { + // unsafe, will throw ArrayStoreException if types are not compatible, see javadoc + @SuppressWarnings("unchecked") + final T unchecked = (T) current; + array[i++] = unchecked; + } + } + while (i < array.length) { + array[i++] = null; + } + return array; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + if (object instanceof MultiSet == false) { + return false; + } + final MultiSet other = (MultiSet) object; + if (other.size() != size()) { + return false; + } + for (final E element : map.keySet()) { + if (other.getCount(element) != getCount(element)) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + int total = 0; + for (final Map.Entry entry : map.entrySet()) { + final E element = entry.getKey(); + final MutableInteger count = entry.getValue(); + total += (element == null ? 0 : element.hashCode()) ^ count.value; + } + return total; + } +} diff --git a/src/org/apache/commons/collections4/multiset/AbstractMultiSet.java b/src/org/apache/commons/collections4/multiset/AbstractMultiSet.java new file mode 100644 index 0000000..ddfef0c --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/AbstractMultiSet.java @@ -0,0 +1,509 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multiset; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import org.apache.commons.collections4.IteratorUtils; +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.Transformer; + +/** + * Abstract implementation of the {@link MultiSet} interface to simplify the + * creation of subclass implementations. + * + * @since 4.1 + * @version $Id: AbstractMultiSet.java 1715563 2015-11-21 20:13:35Z tn $ + */ +public abstract class AbstractMultiSet extends AbstractCollection implements MultiSet { + + /** View of the elements */ + private transient Set uniqueSet; + /** View of the entries */ + private transient Set> entrySet; + + /** + * Constructor needed for subclass serialisation. + */ + protected AbstractMultiSet() { + super(); + } + + //----------------------------------------------------------------------- + /** + * Returns the number of elements in this multiset. + * + * @return current size of the multiset + */ + @Override + public int size() { + int totalSize = 0; + for (Entry entry : entrySet()) { + totalSize += entry.getCount(); + } + return totalSize; + } + + /** + * Returns the number of occurrence of the given element in this multiset by + * iterating over its entrySet. + * + * @param object the object to search for + * @return the number of occurrences of the object, zero if not found + */ + @Override + public int getCount(final Object object) { + for (Entry entry : entrySet()) { + final E element = entry.getElement(); + if (element == object || + element != null && element.equals(object)) { + return entry.getCount(); + } + } + return 0; + } + + @Override + public int setCount(final E object, final int count) { + if (count < 0) { + throw new IllegalArgumentException("Count must not be negative."); + } + + int oldCount = getCount(object); + if (oldCount < count) { + add(object, count - oldCount); + } else { + remove(object, oldCount - count); + } + return oldCount; + } + + //----------------------------------------------------------------------- + /** + * Determines if the multiset contains the given element. + * + * @param object the object to search for + * @return true if the multiset contains the given element + */ + @Override + public boolean contains(final Object object) { + return getCount(object) > 0; + } + + //----------------------------------------------------------------------- + /** + * Gets an iterator over the multiset elements. Elements present in the + * MultiSet more than once will be returned repeatedly. + * + * @return the iterator + */ + @Override + public Iterator iterator() { + return new MultiSetIterator(this); + } + + /** + * Inner class iterator for the MultiSet. + */ + private static class MultiSetIterator implements Iterator { + private final AbstractMultiSet parent; + private final Iterator> entryIterator; + private Entry current; + private int itemCount; + private boolean canRemove; + + /** + * Constructor. + * + * @param parent the parent multiset + */ + public MultiSetIterator(final AbstractMultiSet parent) { + this.parent = parent; + this.entryIterator = parent.entrySet().iterator(); + this.current = null; + this.canRemove = false; + } + + /** {@inheritDoc} */ + @Override + public boolean hasNext() { + return itemCount > 0 || entryIterator.hasNext(); + } + + /** {@inheritDoc} */ + @Override + public E next() { + if (itemCount == 0) { + current = entryIterator.next(); + itemCount = current.getCount(); + } + canRemove = true; + itemCount--; + return current.getElement(); + } + + /** {@inheritDoc} */ + @Override + public void remove() { + if (canRemove == false) { + throw new IllegalStateException(); + } + final int count = current.getCount(); + if (count > 1) { + parent.remove(current.getElement()); + } else { + entryIterator.remove(); + } + canRemove = false; + } + } + + //----------------------------------------------------------------------- + @Override + public boolean add(final E object) { + add(object, 1); + return true; + } + + @Override + public int add(final E object, final int occurrences) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + /** + * Clears the multiset removing all elements from the entrySet. + */ + @Override + public void clear() { + Iterator> it = entrySet().iterator(); + while (it.hasNext()) { + it.next(); + it.remove(); + } + } + + @Override + public boolean remove(final Object object) { + return remove(object, 1) != 0; + } + + @Override + public int remove(final Object object, final int occurrences) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + boolean result = false; + final Iterator i = coll.iterator(); + while (i.hasNext()) { + final Object obj = i.next(); + final boolean changed = remove(obj, getCount(obj)) != 0; + result = result || changed; + } + return result; + } + + //----------------------------------------------------------------------- + /** + * Returns a view of the unique elements of this multiset. + * + * @return the set of unique elements in this multiset + */ + @Override + public Set uniqueSet() { + if (uniqueSet == null) { + uniqueSet = createUniqueSet(); + } + return uniqueSet; + } + + /** + * Create a new view for the set of unique elements in this multiset. + * + * @return a view of the set of unique elements + */ + protected Set createUniqueSet() { + return new UniqueSet(this); + } + + /** + * Creates a unique set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the uniqueSet iterator + */ + protected Iterator createUniqueSetIterator() { + final Transformer, E> transformer = new Transformer, E>() { + @Override + public E transform(Entry entry) { + return entry.getElement(); + } + }; + return IteratorUtils.transformedIterator(entrySet().iterator(), transformer); + } + + /** + * Returns an unmodifiable view of the entries of this multiset. + * + * @return the set of entries in this multiset + */ + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = createEntrySet(); + } + return entrySet; + } + + /** + * Create a new view for the set of entries in this multiset. + * + * @return a view of the set of entries + */ + protected Set> createEntrySet() { + return new EntrySet(this); + } + + /** + * Returns the number of unique elements in this multiset. + * + * @return the number of unique elements + */ + protected abstract int uniqueElements(); + + /** + * Creates an entry set iterator. + * Subclasses can override this to return iterators with different properties. + * + * @return the entrySet iterator + */ + protected abstract Iterator> createEntrySetIterator(); + + //----------------------------------------------------------------------- + /** + * Inner class UniqueSet. + */ + protected static class UniqueSet extends AbstractSet { + + /** The parent multiset */ + protected final AbstractMultiSet parent; + + /** + * Constructs a new unique element view of the MultiSet. + * + * @param parent the parent MultiSet + */ + protected UniqueSet(final AbstractMultiSet parent) { + this.parent = parent; + } + + @Override + public Iterator iterator() { + return parent.createUniqueSetIterator(); + } + + @Override + public boolean contains(final Object key) { + return parent.contains(key); + } + + @Override + public boolean containsAll(final Collection coll) { + return parent.containsAll(coll); + } + + @Override + public boolean remove(final Object key) { + return parent.remove(key, parent.getCount(key)) != 0; + } + + @Override + public int size() { + return parent.uniqueElements(); + } + + @Override + public void clear() { + parent.clear(); + } + } + + //----------------------------------------------------------------------- + /** + * Inner class EntrySet. + */ + protected static class EntrySet extends AbstractSet> { + + private final AbstractMultiSet parent; + + /** + * Constructs a new view of the MultiSet. + * + * @param parent the parent MultiSet + */ + protected EntrySet(final AbstractMultiSet parent) { + this.parent = parent; + } + + @Override + public int size() { + return parent.uniqueElements(); + } + + @Override + public Iterator> iterator() { + return parent.createEntrySetIterator(); + } + + @Override + public boolean contains(final Object obj) { + if (obj instanceof Entry == false) { + return false; + } + final Entry entry = (Entry) obj; + final Object element = entry.getElement(); + return parent.getCount(element) == entry.getCount(); + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Entry == false) { + return false; + } + final Entry entry = (Entry) obj; + final Object element = entry.getElement(); + if (parent.contains(element)) { + final int count = parent.getCount(element); + if (entry.getCount() == count) { + parent.remove(element, count); + return true; + } + } + return false; + } + } + + /** + * Inner class AbstractEntry. + */ + protected static abstract class AbstractEntry implements Entry { + + @Override + public boolean equals(Object object) { + if (object instanceof Entry) { + final Entry other = (Entry) object; + final E element = this.getElement(); + final Object otherElement = other.getElement(); + + return this.getCount() == other.getCount() && + (element == otherElement || + element != null && element.equals(otherElement)); + } + return false; + } + + @Override + public int hashCode() { + final E element = getElement(); + return ((element == null) ? 0 : element.hashCode()) ^ getCount(); + } + + @Override + public String toString() { + return String.format("%s:%d", getElement(), getCount()); + } + + } + + //----------------------------------------------------------------------- + /** + * Write the multiset out using a custom routine. + * @param out the output stream + * @throws IOException any of the usual I/O related exceptions + */ + protected void doWriteObject(final ObjectOutputStream out) throws IOException { + out.writeInt(entrySet().size()); + for (final Entry entry : entrySet()) { + out.writeObject(entry.getElement()); + out.writeInt(entry.getCount()); + } + } + + /** + * Read the multiset in using a custom routine. + * @param in the input stream + * @throws IOException any of the usual I/O related exceptions + * @throws ClassNotFoundException if the stream contains an object which class can not be loaded + * @throws ClassCastException if the stream does not contain the correct objects + */ + protected void doReadObject(final ObjectInputStream in) + throws IOException, ClassNotFoundException { + final int entrySize = in.readInt(); + for (int i = 0; i < entrySize; i++) { + @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect + final E obj = (E) in.readObject(); + final int count = in.readInt(); + setCount(obj, count); + } + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + if (object instanceof MultiSet == false) { + return false; + } + final MultiSet other = (MultiSet) object; + if (other.size() != size()) { + return false; + } + for (final Entry entry : entrySet()) { + if (other.getCount(entry.getElement()) != getCount(entry.getElement())) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return entrySet().hashCode(); + } + + /** + * Implement a toString() method suitable for debugging. + * + * @return a debugging toString + */ + @Override + public String toString() { + return entrySet().toString(); + } + +} diff --git a/src/org/apache/commons/collections4/multiset/AbstractMultiSetDecorator.java b/src/org/apache/commons/collections4/multiset/AbstractMultiSetDecorator.java new file mode 100644 index 0000000..8838d16 --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/AbstractMultiSetDecorator.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multiset; + +import java.util.Set; + +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.collection.AbstractCollectionDecorator; + +/** + * Decorates another MultSet to provide additional behaviour. + *

              + * Methods are forwarded directly to the decorated multiset. + * + * @since 4.1 + * @version $Id: AbstractMultiSetDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractMultiSetDecorator + extends AbstractCollectionDecorator implements MultiSet { + + /** Serialization version */ + private static final long serialVersionUID = 20150610L; + + /** + * Constructor only used in deserialization, do not use otherwise. + */ + protected AbstractMultiSetDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param multiset the multiset to decorate, must not be null + * @throws NullPointerException if multiset is null + */ + protected AbstractMultiSetDecorator(final MultiSet multiset) { + super(multiset); + } + + /** + * Gets the multiset being decorated. + * + * @return the decorated multiset + */ + @Override + protected MultiSet decorated() { + return (MultiSet) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + @Override + public int getCount(final Object object) { + return decorated().getCount(object); + } + + @Override + public int setCount(E object, int count) { + return decorated().setCount(object, count); + } + + @Override + public int add(final E object, final int count) { + return decorated().add(object, count); + } + + @Override + public int remove(final Object object, final int count) { + return decorated().remove(object, count); + } + + @Override + public Set uniqueSet() { + return decorated().uniqueSet(); + } + + @Override + public Set> entrySet() { + return decorated().entrySet(); + } + +} diff --git a/src/org/apache/commons/collections4/multiset/HashMultiSet.java b/src/org/apache/commons/collections4/multiset/HashMultiSet.java new file mode 100644 index 0000000..0474223 --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/HashMultiSet.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multiset; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; + +/** + * Implements {@code MultiSet}, using a {@link HashMap} to provide the + * data storage. This is the standard implementation of a multiset. + *

              + * A {@code MultiSet} stores each object in the collection together with a + * count of occurrences. Extra methods on the interface allow multiple copies + * of an object to be added or removed at once. + * + * @since 4.1 + * @version $Id: HashMultiSet.java 1715563 2015-11-21 20:13:35Z tn $ + */ +public class HashMultiSet extends AbstractMapMultiSet implements Serializable { + + /** Serial version lock */ + private static final long serialVersionUID = 20150610L; + + /** + * Constructs an empty {@link HashMultiSet}. + */ + public HashMultiSet() { + super(new HashMap()); + } + + /** + * Constructs a multiset containing all the members of the given collection. + * + * @param coll a collection to copy into this multiset + */ + public HashMultiSet(final Collection coll) { + this(); + addAll(coll); + } + + //----------------------------------------------------------------------- + /** + * Write the multiset out using a custom routine. + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + super.doWriteObject(out); + } + + /** + * Read the multiset in using a custom routine. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setMap(new HashMap()); + super.doReadObject(in); + } + +} diff --git a/src/org/apache/commons/collections4/multiset/PredicatedMultiSet.java b/src/org/apache/commons/collections4/multiset/PredicatedMultiSet.java new file mode 100644 index 0000000..2518bbb --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/PredicatedMultiSet.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multiset; + +import java.util.Set; + +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.collection.PredicatedCollection; + +/** + * Decorates another {@link MultiSet} to validate that additions + * match a specified predicate. + *

              + * This multiset exists to provide validation for the decorated multiset. + * It is normally created to decorate an empty multiset. + * If an object cannot be added to the multiset, an {@link IllegalArgumentException} + * is thrown. + *

              + * One usage would be to ensure that no null entries are added to the multiset. + *

              + * MultiSet<E> set =
              + *      PredicatedMultiSet.predicatedMultiSet(new HashMultiSet<E>(),
              + *                                            NotNullPredicate.notNullPredicate());
              + * 
              + * + * @since 4.1 + * @version $Id: PredicatedMultiSet.java 1688308 2015-06-29 21:28:54Z tn $ + */ +public class PredicatedMultiSet extends PredicatedCollection implements MultiSet { + + /** Serialization version */ + private static final long serialVersionUID = 20150629L; + + /** + * Factory method to create a predicated (validating) multiset. + *

              + * If there are any elements already in the multiset being decorated, they + * are validated. + * + * @param the type of the elements in the multiset + * @param multiset the multiset to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated MultiSet + * @throws NullPointerException if multiset or predicate is null + * @throws IllegalArgumentException if the multiset contains invalid elements + */ + public static PredicatedMultiSet predicatedMultiSet(final MultiSet multiset, + final Predicate predicate) { + return new PredicatedMultiSet(multiset, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the multiset being decorated, they + * are validated. + * + * @param multiset the multiset to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if multiset or predicate is null + * @throws IllegalArgumentException if the multiset contains invalid elements + */ + protected PredicatedMultiSet(final MultiSet multiset, final Predicate predicate) { + super(multiset, predicate); + } + + /** + * Gets the decorated multiset. + * + * @return the decorated multiset + */ + @Override + protected MultiSet decorated() { + return (MultiSet) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + //----------------------------------------------------------------------- + + @Override + public int add(final E object, final int count) { + validate(object); + return decorated().add(object, count); + } + + @Override + public int remove(final Object object, final int count) { + return decorated().remove(object, count); + } + + @Override + public int getCount(final Object object) { + return decorated().getCount(object); + } + + @Override + public int setCount(E object, int count) { + validate(object); + return decorated().setCount(object, count); + } + + @Override + public Set uniqueSet() { + return decorated().uniqueSet(); + } + + @Override + public Set> entrySet() { + return decorated().entrySet(); + } + +} diff --git a/src/org/apache/commons/collections4/multiset/SynchronizedMultiSet.java b/src/org/apache/commons/collections4/multiset/SynchronizedMultiSet.java new file mode 100644 index 0000000..96d6a67 --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/SynchronizedMultiSet.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multiset; + +import java.util.Set; + +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.collection.SynchronizedCollection; + +/** + * Decorates another {@link MultiSet} to synchronize its behaviour + * for a multi-threaded environment. + *

              + * Methods are synchronized, then forwarded to the decorated multiset. + * Iterators must be separately synchronized around the loop. + * + * @since 4.1 + * @version $Id: SynchronizedMultiSet.java 1714424 2015-11-15 10:06:16Z tn $ + */ +public class SynchronizedMultiSet extends SynchronizedCollection implements MultiSet { + + /** Serialization version */ + private static final long serialVersionUID = 20150629L; + + /** + * Factory method to create a synchronized multiset. + * + * @param the type of the elements in the multiset + * @param multiset the multiset to decorate, must not be null + * @return a new synchronized MultiSet + * @throws NullPointerException if multiset is null + */ + public static SynchronizedMultiSet synchronizedMultiSet(final MultiSet multiset) { + return new SynchronizedMultiSet(multiset); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param multiset the multiset to decorate, must not be null + * @throws NullPointerException if multiset is null + */ + protected SynchronizedMultiSet(final MultiSet multiset) { + super(multiset); + } + + /** + * Constructor that wraps (not copies). + * + * @param multiset the multiset to decorate, must not be null + * @param lock the lock to use, must not be null + * @throws NullPointerException if multiset or lock is null + */ + protected SynchronizedMultiSet(final MultiSet multiset, final Object lock) { + super(multiset, lock); + } + + /** + * Gets the multiset being decorated. + * + * @return the decorated multiset + */ + @Override + protected MultiSet decorated() { + return (MultiSet) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + synchronized (lock) { + return decorated().equals(object); + } + } + + @Override + public int hashCode() { + synchronized (lock) { + return decorated().hashCode(); + } + } + + //----------------------------------------------------------------------- + + @Override + public int add(final E object, final int count) { + synchronized (lock) { + return decorated().add(object, count); + } + } + + @Override + public int remove(final Object object, final int count) { + synchronized (lock) { + return decorated().remove(object, count); + } + } + + @Override + public int getCount(final Object object) { + synchronized (lock) { + return decorated().getCount(object); + } + } + + @Override + public int setCount(E object, int count) { + synchronized (lock) { + return decorated().setCount(object, count); + } + } + + @Override + public Set uniqueSet() { + synchronized (lock) { + final Set set = decorated().uniqueSet(); + return new SynchronizedSet(set, lock); + } + } + + @Override + public Set> entrySet() { + synchronized (lock) { + final Set> set = decorated().entrySet(); + return new SynchronizedSet>(set, lock); + } + } + + //----------------------------------------------------------------------- + /** + * Synchronized Set for the MultiSet class. + */ + static class SynchronizedSet extends SynchronizedCollection implements Set { + /** Serialization version */ + private static final long serialVersionUID = 20150629L; + + /** + * Constructor. + * @param set the set to decorate + * @param lock the lock to use, shared with the multiset + */ + SynchronizedSet(final Set set, final Object lock) { + super(set, lock); + } + } + +} diff --git a/src/org/apache/commons/collections4/multiset/UnmodifiableMultiSet.java b/src/org/apache/commons/collections4/multiset/UnmodifiableMultiSet.java new file mode 100644 index 0000000..abb380e --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/UnmodifiableMultiSet.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.multiset; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import org.apache.commons.collections4.MultiSet; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; +import org.apache.commons.collections4.set.UnmodifiableSet; + +/** + * Decorates another {@link MultiSet} to ensure it can't be altered. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 4.1 + * @version $Id: UnmodifiableMultiSet.java 1684982 2015-06-11 22:05:50Z tn $ + */ +public final class UnmodifiableMultiSet + extends AbstractMultiSetDecorator implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = 20150611L; + + /** + * Factory method to create an unmodifiable multiset. + *

              + * If the multiset passed in is already unmodifiable, it is returned. + * + * @param the type of the elements in the multiset + * @param multiset the multiset to decorate, may not be null + * @return an unmodifiable MultiSet + * @throws NullPointerException if multiset is null + */ + public static MultiSet unmodifiableMultiSet(final MultiSet multiset) { + if (multiset instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final MultiSet tmpMultiSet = (MultiSet) multiset; + return tmpMultiSet; + } + return new UnmodifiableMultiSet(multiset); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param multiset the multiset to decorate, may not be null + * @throws NullPointerException if multiset is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableMultiSet(final MultiSet multiset) { + super((MultiSet) multiset); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @throws ClassCastException if deserialised object has wrong type + */ + @SuppressWarnings("unchecked") // will throw CCE, see Javadoc + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator. unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public int setCount(E object, int count) { + throw new UnsupportedOperationException(); + } + + @Override + public int add(final E object, final int count) { + throw new UnsupportedOperationException(); + } + + @Override + public int remove(final Object object, final int count) { + throw new UnsupportedOperationException(); + } + + @Override + public Set uniqueSet() { + final Set set = decorated().uniqueSet(); + return UnmodifiableSet.unmodifiableSet(set); + } + + @Override + public Set> entrySet() { + final Set> set = decorated().entrySet(); + return UnmodifiableSet.unmodifiableSet(set); + } + +} diff --git a/src/org/apache/commons/collections4/multiset/package-info.java b/src/org/apache/commons/collections4/multiset/package-info.java new file mode 100644 index 0000000..49c07f7 --- /dev/null +++ b/src/org/apache/commons/collections4/multiset/package-info.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the + * {@link org.apache.commons.collections4.MultiSet MultiSet} and + * {@link org.apache.commons.collections4.SortedMultiSet SortedMultiSet} interfaces. + * A multiset stores an object and a count of the number of occurrences of the object. + *

              + * The following implementations are provided in the package: + *

                + *
              • HashMultiSet - implementation that uses a HashMap to store the data + *
              • TreeMultiSet - implementation that uses a TreeMap to store the data + *
              + *

              + * The following decorators are provided in the package: + *

                + *
              • Predicated - ensures that only elements that are valid according to a predicate can be added + *
              • Synchronized - synchronizes method access for multi-threaded environments + *
              • Unmodifiable - ensures the multiset cannot be altered + *
              + * + * @version $Id: package-info.java 1688308 2015-06-29 21:28:54Z tn $ + */ +package org.apache.commons.collections4.multiset; diff --git a/src/org/apache/commons/collections4/overview.html b/src/org/apache/commons/collections4/overview.html new file mode 100644 index 0000000..9a664e7 --- /dev/null +++ b/src/org/apache/commons/collections4/overview.html @@ -0,0 +1,113 @@ + + + +

              + Commons-Collections contains implementations, enhancements and utilities + that complement the Java Collections Framework. +

              +

              + The Apache Commons Collections Framework component adds a significant + amount of enhancements to the standard JDK collections. These enhancements + come in the form of new interfaces, new implementations and utility classes. +

              +

              + See also the java.util package for the standard Java collections. +

              + +

              Main features

              +

              + Commons-Collections defines a number of key interfaces: +

              + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              InterfaceDescription
              + {@link org.apache.commons.collections.Bag} + + A new Collection subinterface that stores each object together + with the number of occurrences. Methods are provided to get the number of + occurrences, and to add and remove a certain number of that object. +
              + {@link org.apache.commons.collections.Buffer} + + A new Collection subinterface that allows objects to be removed + in some well-defined order. Methods enable the next item to be peeked and removed. +
              + {@link org.apache.commons.collections.BidiMap} + + A new Map subinterface that allows lookup from key to value and + from value to key with equal ease. +
              + {@link org.apache.commons.collections.OrderedMap} + + A new Map subinterface that is used when a map has an order, but is + not sorted. Methods enable bidirectional iteration through the map. +
              + {@link org.apache.commons.collections.MapIterator} + + A new Iterator subinterface specially designed for maps. This iterator + avoids the need for entrySet iteration of a map, and is simpler to use. +
              + {@link org.apache.commons.collections.ResettableIterator} + + A new Iterator subinterface that allows the iteration to be reset back + to the start. Many iterators in this library have this functionality. +
              + {@link org.apache.commons.collections.Closure}
              + {@link org.apache.commons.collections.Predicate}
              + {@link org.apache.commons.collections.Transformer}
              + {@link org.apache.commons.collections.Factory}
              +
              + A group of functor interfaces that provide plugin behaviour to various + collections and utilities. +
              +

              + In addition to the interfaces, there are many implementations. + Consult each subpackage for full details of these. +

              + + diff --git a/src/org/apache/commons/collections4/package-info.java b/src/org/apache/commons/collections4/package-info.java new file mode 100644 index 0000000..7e44dc4 --- /dev/null +++ b/src/org/apache/commons/collections4/package-info.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains the interfaces and utilities shared across all the subpackages of this component. + *

              + * The following collection implementations are provided in the package: + *

                + *
              • ArrayStack - a non synchronized Stack that follows the same API as {@code java.util Stack} + *
              + * + * @version $Id: package-info.java 1469004 2013-04-17 17:37:03Z tn $ + */ +package org.apache.commons.collections4; diff --git a/src/org/apache/commons/collections4/queue/AbstractQueueDecorator.java b/src/org/apache/commons/collections4/queue/AbstractQueueDecorator.java new file mode 100644 index 0000000..8623832 --- /dev/null +++ b/src/org/apache/commons/collections4/queue/AbstractQueueDecorator.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.queue; + +import java.util.Queue; + +import org.apache.commons.collections4.collection.AbstractCollectionDecorator; + +/** + * Decorates another {@link Queue} to provide additional behaviour. + *

              + * Methods are forwarded directly to the decorated queue. + *

              + * This implementation does not forward the hashCode and equals methods through + * to the backing object, but relies on Object's implementation. This is + * necessary as some Queue implementations, e.g. LinkedList, have custom a + * equals implementation for which symmetry can not be preserved. + * See class javadoc of AbstractCollectionDecorator for more information. + * + * @param the type of the elements in the queue + * @since 4.0 + * @version $Id: AbstractQueueDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractQueueDecorator extends AbstractCollectionDecorator + implements Queue { + + /** Serialization version */ + private static final long serialVersionUID = -2629815475789577029L; + + /** + * Constructor only used in deserialization, do not use otherwise. + */ + protected AbstractQueueDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param queue the queue to decorate, must not be null + * @throws NullPointerException if queue is null + */ + protected AbstractQueueDecorator(final Queue queue) { + super(queue); + } + + /** + * Gets the queue being decorated. + * + * @return the decorated queue + */ + @Override + protected Queue decorated() { + return (Queue) super.decorated(); + } + + //----------------------------------------------------------------------- + + public boolean offer(final E obj) { + return decorated().offer(obj); + } + + public E poll() { + return decorated().poll(); + } + + public E peek() { + return decorated().peek(); + } + + public E element() { + return decorated().element(); + } + + public E remove() { + return decorated().remove(); + } + +} diff --git a/src/org/apache/commons/collections4/queue/CircularFifoQueue.java b/src/org/apache/commons/collections4/queue/CircularFifoQueue.java new file mode 100644 index 0000000..5fd8ba9 --- /dev/null +++ b/src/org/apache/commons/collections4/queue/CircularFifoQueue.java @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.queue; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.AbstractCollection; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Queue; + +import org.apache.commons.collections4.BoundedCollection; + +/** + * CircularFifoQueue is a first-in first-out queue with a fixed size that + * replaces its oldest element if full. + *

              + * The removal order of a {@link CircularFifoQueue} is based on the + * insertion order; elements are removed in the same order in which they + * were added. The iteration order is the same as the removal order. + *

              + * The {@link #add(Object)}, {@link #remove()}, {@link #peek()}, {@link #poll}, + * {@link #offer(Object)} operations all perform in constant time. + * All other operations perform in linear time or worse. + *

              + * This queue prevents null objects from being added. + * + * @since 4.0 + * @version $Id: CircularFifoQueue.java 1648957 2015-01-01 22:01:31Z tn $ + */ +public class CircularFifoQueue extends AbstractCollection + implements Queue, BoundedCollection, Serializable { + + /** Serialization version. */ + private static final long serialVersionUID = -8423413834657610406L; + + /** Underlying storage array. */ + private transient E[] elements; + + /** Array index of first (oldest) queue element. */ + private transient int start = 0; + + /** + * Index mod maxElements of the array position following the last queue + * element. Queue elements start at elements[start] and "wrap around" + * elements[maxElements-1], ending at elements[decrement(end)]. + * For example, elements = {c,a,b}, start=1, end=1 corresponds to + * the queue [a,b,c]. + */ + private transient int end = 0; + + /** Flag to indicate if the queue is currently full. */ + private transient boolean full = false; + + /** Capacity of the queue. */ + private final int maxElements; + + /** + * Constructor that creates a queue with the default size of 32. + */ + public CircularFifoQueue() { + this(32); + } + + /** + * Constructor that creates a queue with the specified size. + * + * @param size the size of the queue (cannot be changed) + * @throws IllegalArgumentException if the size is < 1 + */ + @SuppressWarnings("unchecked") + public CircularFifoQueue(final int size) { + if (size <= 0) { + throw new IllegalArgumentException("The size must be greater than 0"); + } + elements = (E[]) new Object[size]; + maxElements = elements.length; + } + + /** + * Constructor that creates a queue from the specified collection. + * The collection size also sets the queue size. + * + * @param coll the collection to copy into the queue, may not be null + * @throws NullPointerException if the collection is null + */ + public CircularFifoQueue(final Collection coll) { + this(coll.size()); + addAll(coll); + } + + //----------------------------------------------------------------------- + /** + * Write the queue out using a custom routine. + * + * @param out the output stream + * @throws IOException if an I/O error occurs while writing to the output stream + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeInt(size()); + for (final E e : this) { + out.writeObject(e); + } + } + + /** + * Read the queue in using a custom routine. + * + * @param in the input stream + * @throws IOException if an I/O error occurs while writing to the output stream + * @throws ClassNotFoundException if the class of a serialized object can not be found + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + elements = (E[]) new Object[maxElements]; + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + elements[i] = (E) in.readObject(); + } + start = 0; + full = size == maxElements; + if (full) { + end = 0; + } else { + end = size; + } + } + + //----------------------------------------------------------------------- + /** + * Returns the number of elements stored in the queue. + * + * @return this queue's size + */ + @Override + public int size() { + int size = 0; + + if (end < start) { + size = maxElements - start + end; + } else if (end == start) { + size = full ? maxElements : 0; + } else { + size = end - start; + } + + return size; + } + + /** + * Returns true if this queue is empty; false otherwise. + * + * @return true if this queue is empty + */ + @Override + public boolean isEmpty() { + return size() == 0; + } + + /** + * {@inheritDoc} + *

              + * A {@code CircularFifoQueue} can never be full, thus this returns always + * {@code false}. + * + * @return always returns {@code false} + */ + public boolean isFull() { + return false; + } + + /** + * Returns {@code true} if the capacity limit of this queue has been reached, + * i.e. the number of elements stored in the queue equals its maximum size. + * + * @return {@code true} if the capacity limit has been reached, {@code false} otherwise + * @since 4.1 + */ + public boolean isAtFullCapacity() { + return size() == maxElements; + } + + /** + * Gets the maximum size of the collection (the bound). + * + * @return the maximum number of elements the collection can hold + */ + public int maxSize() { + return maxElements; + } + + /** + * Clears this queue. + */ + @Override + public void clear() { + full = false; + start = 0; + end = 0; + Arrays.fill(elements, null); + } + + /** + * Adds the given element to this queue. If the queue is full, the least recently added + * element is discarded so that a new element can be inserted. + * + * @param element the element to add + * @return true, always + * @throws NullPointerException if the given element is null + */ + @Override + public boolean add(final E element) { + if (null == element) { + throw new NullPointerException("Attempted to add null object to queue"); + } + + if (isAtFullCapacity()) { + remove(); + } + + elements[end++] = element; + + if (end >= maxElements) { + end = 0; + } + + if (end == start) { + full = true; + } + + return true; + } + + /** + * Returns the element at the specified position in this queue. + * + * @param index the position of the element in the queue + * @return the element at position {@code index} + * @throws NoSuchElementException if the requested position is outside the range [0, size) + */ + public E get(final int index) { + final int sz = size(); + if (index < 0 || index >= sz) { + throw new NoSuchElementException( + String.format("The specified index (%1$d) is outside the available range [0, %2$d)", + Integer.valueOf(index), Integer.valueOf(sz))); + } + + final int idx = (start + index) % maxElements; + return elements[idx]; + } + + //----------------------------------------------------------------------- + + /** + * Adds the given element to this queue. If the queue is full, the least recently added + * element is discarded so that a new element can be inserted. + * + * @param element the element to add + * @return true, always + * @throws NullPointerException if the given element is null + */ + public boolean offer(E element) { + return add(element); + } + + public E poll() { + if (isEmpty()) { + return null; + } + return remove(); + } + + public E element() { + if (isEmpty()) { + throw new NoSuchElementException("queue is empty"); + } + return peek(); + } + + public E peek() { + if (isEmpty()) { + return null; + } + return elements[start]; + } + + public E remove() { + if (isEmpty()) { + throw new NoSuchElementException("queue is empty"); + } + + final E element = elements[start]; + if (null != element) { + elements[start++] = null; + + if (start >= maxElements) { + start = 0; + } + full = false; + } + return element; + } + + //----------------------------------------------------------------------- + /** + * Increments the internal index. + * + * @param index the index to increment + * @return the updated index + */ + private int increment(int index) { + index++; + if (index >= maxElements) { + index = 0; + } + return index; + } + + /** + * Decrements the internal index. + * + * @param index the index to decrement + * @return the updated index + */ + private int decrement(int index) { + index--; + if (index < 0) { + index = maxElements - 1; + } + return index; + } + + /** + * Returns an iterator over this queue's elements. + * + * @return an iterator over this queue's elements + */ + @Override + public Iterator iterator() { + return new Iterator() { + + private int index = start; + private int lastReturnedIndex = -1; + private boolean isFirst = full; + + public boolean hasNext() { + return isFirst || index != end; + } + + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + isFirst = false; + lastReturnedIndex = index; + index = increment(index); + return elements[lastReturnedIndex]; + } + + public void remove() { + if (lastReturnedIndex == -1) { + throw new IllegalStateException(); + } + + // First element can be removed quickly + if (lastReturnedIndex == start) { + CircularFifoQueue.this.remove(); + lastReturnedIndex = -1; + return; + } + + int pos = lastReturnedIndex + 1; + if (start < lastReturnedIndex && pos < end) { + // shift in one part + System.arraycopy(elements, pos, elements, lastReturnedIndex, end - pos); + } else { + // Other elements require us to shift the subsequent elements + while (pos != end) { + if (pos >= maxElements) { + elements[pos - 1] = elements[0]; + pos = 0; + } else { + elements[decrement(pos)] = elements[pos]; + pos = increment(pos); + } + } + } + + lastReturnedIndex = -1; + end = decrement(end); + elements[end] = null; + full = false; + index = decrement(index); + } + + }; + } + +} diff --git a/src/org/apache/commons/collections4/queue/PredicatedQueue.java b/src/org/apache/commons/collections4/queue/PredicatedQueue.java new file mode 100644 index 0000000..ffbe128 --- /dev/null +++ b/src/org/apache/commons/collections4/queue/PredicatedQueue.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.queue; + +import java.util.Queue; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.collection.PredicatedCollection; + +/** + * Decorates another {@link Queue} to validate that additions + * match a specified predicate. + *

              + * This queue exists to provide validation for the decorated queue. + * It is normally created to decorate an empty queue. + * If an object cannot be added to the queue, an IllegalArgumentException is thrown. + *

              + * One usage would be to ensure that no null entries are added to the queue. + *

              Queue queue = PredicatedQueue.predicatedQueue(new UnboundedFifoQueue(), NotNullPredicate.INSTANCE);
              + * + * @since 4.0 + * @version $Id: PredicatedQueue.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedQueue extends PredicatedCollection implements Queue { + + /** Serialization version */ + private static final long serialVersionUID = 2307609000539943581L; + + /** + * Factory method to create a predicated (validating) queue. + *

              + * If there are any elements already in the queue being decorated, they + * are validated. + * + * @param the type of the elements in the queue + * @param Queue the queue to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated queue + * @throws NullPointerException if queue or predicate is null + * @throws IllegalArgumentException if the queue contains invalid elements + */ + public static PredicatedQueue predicatedQueue(final Queue Queue, + final Predicate predicate) { + return new PredicatedQueue(Queue, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the collection being decorated, they + * are validated. + * + * @param queue the queue to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if queue or predicate is null + * @throws IllegalArgumentException if the Queue contains invalid elements + */ + protected PredicatedQueue(final Queue queue, final Predicate predicate) { + super(queue, predicate); + } + + /** + * Gets the queue being decorated. + * + * @return the decorated queue + */ + @Override + protected Queue decorated() { + return (Queue) super.decorated(); + } + + //----------------------------------------------------------------------- + + /** + * Override to validate the object being added to ensure it matches + * the predicate. + * + * @param object the object being added + * @return the result of adding to the underlying queue + * @throws IllegalArgumentException if the add is invalid + */ + public boolean offer(final E object) { + validate(object); + return decorated().offer(object); + } + + public E poll() { + return decorated().poll(); + } + + public E peek() { + return decorated().peek(); + } + + public E element() { + return decorated().element(); + } + + public E remove() { + return decorated().remove(); + } + +} diff --git a/src/org/apache/commons/collections4/queue/TransformedQueue.java b/src/org/apache/commons/collections4/queue/TransformedQueue.java new file mode 100644 index 0000000..c217ad5 --- /dev/null +++ b/src/org/apache/commons/collections4/queue/TransformedQueue.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.queue; + +import java.util.Queue; + +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.collection.TransformedCollection; + +/** + * Decorates another {@link Queue} to transform objects that are added. + *

              + * The add/offer methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + * + * @since 4.0 + * @version $Id: TransformedQueue.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedQueue extends TransformedCollection implements Queue { + + /** Serialization version */ + private static final long serialVersionUID = -7901091318986132033L; + + /** + * Factory method to create a transforming queue. + *

              + * If there are any elements already in the queue being decorated, they + * are NOT transformed. + * Contrast this with {@link #transformedQueue(Queue, Transformer)}. + * + * @param the type of the elements in the queue + * @param queue the queue to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed Queue + * @throws NullPointerException if queue or transformer is null + */ + public static TransformedQueue transformingQueue(final Queue queue, + final Transformer transformer) { + return new TransformedQueue(queue, transformer); + } + + /** + * Factory method to create a transforming queue that will transform + * existing contents of the specified queue. + *

              + * If there are any elements already in the queue being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingQueue(Queue, Transformer)}. + * + * @param the type of the elements in the queue + * @param queue the queue to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed Queue + * @throws NullPointerException if queue or transformer is null + * @since 4.0 + */ + public static TransformedQueue transformedQueue(final Queue queue, + final Transformer transformer) { + // throws IAE if queue or transformer is null + final TransformedQueue decorated = new TransformedQueue(queue, transformer); + if (queue.size() > 0) { + @SuppressWarnings("unchecked") // queue is type + final E[] values = (E[]) queue.toArray(); // NOPMD - false positive for generics + queue.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the queue being decorated, they + * are NOT transformed. + * + * @param queue the queue to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if queue or transformer is null + */ + protected TransformedQueue(final Queue queue, final Transformer transformer) { + super(queue, transformer); + } + + /** + * Gets the decorated queue. + * + * @return the decorated queue + */ + protected Queue getQueue() { + return (Queue) decorated(); + } + + //----------------------------------------------------------------------- + + public boolean offer(final E obj) { + return getQueue().offer(transform(obj)); + } + + public E poll() { + return getQueue().poll(); + } + + public E peek() { + return getQueue().peek(); + } + + public E element() { + return getQueue().element(); + } + + public E remove() { + return getQueue().remove(); + } + +} diff --git a/src/org/apache/commons/collections4/queue/UnmodifiableQueue.java b/src/org/apache/commons/collections4/queue/UnmodifiableQueue.java new file mode 100644 index 0000000..659099f --- /dev/null +++ b/src/org/apache/commons/collections4/queue/UnmodifiableQueue.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.queue; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.Queue; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; + +/** + * Decorates another {@link Queue} to ensure it can't be altered. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 4.0 + * @version $Id: UnmodifiableQueue.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableQueue + extends AbstractQueueDecorator + implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = 1832948656215393357L; + + /** + * Factory method to create an unmodifiable queue. + *

              + * If the queue passed in is already unmodifiable, it is returned. + * + * @param the type of the elements in the queue + * @param queue the queue to decorate, must not be null + * @return an unmodifiable Queue + * @throws NullPointerException if queue is null + */ + public static Queue unmodifiableQueue(final Queue queue) { + if (queue instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final Queue tmpQueue = (Queue) queue; + return tmpQueue; + } + return new UnmodifiableQueue(queue); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param queue the queue to decorate, must not be null + * @throws NullPointerException if queue is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableQueue(final Queue queue) { + super((Queue) queue); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException if an I/O error occurs while writing to the output stream + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException if an I/O error occurs while reading from the input stream + * @throws ClassNotFoundException if the class of a serialized object can not be found + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + + @Override + public boolean offer(final E obj) { + throw new UnsupportedOperationException(); + } + + @Override + public E poll() { + throw new UnsupportedOperationException(); + } + + @Override + public E remove() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/org/apache/commons/collections4/queue/package-info.java b/src/org/apache/commons/collections4/queue/package-info.java new file mode 100644 index 0000000..8179326 --- /dev/null +++ b/src/org/apache/commons/collections4/queue/package-info.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations for the {@link java.util.Queue Queue} interface. + *

              + * The following implementations are provided in the package: + *

                + *
              • CircularFifoQueue - implements a queue with a fixed size that discards oldest when full + *
              + *

              + * The following decorators are provided in the package: + *

                + *
              • Predicated - ensures that only elements that are valid according to a predicate can be added + *
              • Transformed - transforms elements added to the queue + *
              • Unmodifiable - ensures the collection cannot be altered + *
              + * + * @version $Id: package-info.java 1477765 2013-04-30 18:37:37Z tn $ + */ +package org.apache.commons.collections4.queue; diff --git a/src/org/apache/commons/collections4/sequence/CommandVisitor.java b/src/org/apache/commons/collections4/sequence/CommandVisitor.java new file mode 100644 index 0000000..0b5e612 --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/CommandVisitor.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +/** + * This interface should be implemented by user object to walk + * through {@link EditScript EditScript} objects. + *

              + * Users should implement this interface in order to walk through + * the {@link EditScript EditScript} object created by the comparison + * of two sequences. This is a direct application of the visitor + * design pattern. The {@link EditScript#visit EditScript.visit} + * method takes an object implementing this interface as an argument, + * it will perform the loop over all commands in the script and the + * proper methods of the user class will be called as the commands are + * encountered. + *

              + * The implementation of the user visitor class will depend on the + * need. Here are two examples. + *

              + * The first example is a visitor that build the longest common + * subsequence: + *

              + * import org.apache.commons.collections4.comparators.sequence.CommandVisitor;
              + *
              + * import java.util.ArrayList;
              + *
              + * public class LongestCommonSubSequence implements CommandVisitor {
              + *
              + *   public LongestCommonSubSequence() {
              + *     a = new ArrayList();
              + *   }
              + *
              + *   public void visitInsertCommand(Object object) {
              + *   }
              + *
              + *   public void visitKeepCommand(Object object) {
              + *     a.add(object);
              + *   }
              + *
              + *   public void visitDeleteCommand(Object object) {
              + *   }
              + *
              + *   public Object[] getSubSequence() {
              + *     return a.toArray();
              + *   }
              + *
              + *   private ArrayList a;
              + *
              + * }
              + * 
              + *

              + * The second example is a visitor that shows the commands and the way + * they transform the first sequence into the second one: + *

              + * import org.apache.commons.collections4.comparators.sequence.CommandVisitor;
              + *
              + * import java.util.Arrays;
              + * import java.util.ArrayList;
              + * import java.util.Iterator;
              + *
              + * public class ShowVisitor implements CommandVisitor {
              + *
              + *   public ShowVisitor(Object[] sequence1) {
              + *     v = new ArrayList();
              + *     v.addAll(Arrays.asList(sequence1));
              + *     index = 0;
              + *   }
              + *
              + *   public void visitInsertCommand(Object object) {
              + *     v.insertElementAt(object, index++);
              + *     display("insert", object);
              + *   }
              + *
              + *   public void visitKeepCommand(Object object) {
              + *     ++index;
              + *     display("keep  ", object);
              + *   }
              + *
              + *   public void visitDeleteCommand(Object object) {
              + *     v.remove(index);
              + *     display("delete", object);
              + *   }
              + *
              + *   private void display(String commandName, Object object) {
              + *     System.out.println(commandName + " " + object + " ->" + this);
              + *   }
              + *
              + *   public String toString() {
              + *     StringBuffer buffer = new StringBuffer();
              + *     for (Iterator iter = v.iterator(); iter.hasNext();) {
              + *       buffer.append(' ').append(iter.next());
              + *     }
              + *     return buffer.toString();
              + *   }
              + *
              + *   private ArrayList v;
              + *   private int index;
              + *
              + * }
              + * 
              + * + * @since 4.0 + * @version $Id: CommandVisitor.java 1477760 2013-04-30 18:34:03Z tn $ + */ +public interface CommandVisitor { + + /** + * Method called when an insert command is encountered. + * + * @param object object to insert (this object comes from the second sequence) + */ + void visitInsertCommand(T object); + + /** + * Method called when a keep command is encountered. + * + * @param object object to keep (this object comes from the first sequence) + */ + void visitKeepCommand(T object); + + /** + * Method called when a delete command is encountered. + * + * @param object object to delete (this object comes from the first sequence) + */ + void visitDeleteCommand(T object); + +} diff --git a/src/org/apache/commons/collections4/sequence/DeleteCommand.java b/src/org/apache/commons/collections4/sequence/DeleteCommand.java new file mode 100644 index 0000000..1d0cc93 --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/DeleteCommand.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +/** + * Command representing the deletion of one object of the first sequence. + *

              + * When one object of the first sequence has no corresponding object in the + * second sequence at the right place, the {@link EditScript edit script} + * transforming the first sequence into the second sequence uses an instance of + * this class to represent the deletion of this object. The objects embedded in + * these type of commands always come from the first sequence. + * + * @see SequencesComparator + * @see EditScript + * + * @since 4.0 + * @version $Id: DeleteCommand.java 1477760 2013-04-30 18:34:03Z tn $ + */ +public class DeleteCommand extends EditCommand { + + /** + * Simple constructor. Creates a new instance of {@link DeleteCommand}. + * + * @param object the object of the first sequence that should be deleted + */ + public DeleteCommand(final T object) { + super(object); + } + + /** + * Accept a visitor. When a DeleteCommand accepts a visitor, it calls + * its {@link CommandVisitor#visitDeleteCommand visitDeleteCommand} method. + * + * @param visitor the visitor to be accepted + */ + @Override + public void accept(final CommandVisitor visitor) { + visitor.visitDeleteCommand(getObject()); + } +} diff --git a/src/org/apache/commons/collections4/sequence/EditCommand.java b/src/org/apache/commons/collections4/sequence/EditCommand.java new file mode 100644 index 0000000..f8c7ec9 --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/EditCommand.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +/** + * Abstract base class for all commands used to transform an objects sequence + * into another one. + *

              + * When two objects sequences are compared through the + * {@link SequencesComparator#getScript SequencesComparator.getScript} method, + * the result is provided has a {@link EditScript script} containing the commands + * that progressively transform the first sequence into the second one. + *

              + * There are only three types of commands, all of which are subclasses of this + * abstract class. Each command is associated with one object belonging to at + * least one of the sequences. These commands are {@link InsertCommand + * InsertCommand} which correspond to an object of the second sequence being + * inserted into the first sequence, {@link DeleteCommand DeleteCommand} which + * correspond to an object of the first sequence being removed and + * {@link KeepCommand KeepCommand} which correspond to an object of the first + * sequence which equals an object in the second sequence. It is + * guaranteed that comparison is always performed this way (i.e. the + * equals method of the object from the first sequence is used and + * the object passed as an argument comes from the second sequence) ; this can + * be important if subclassing is used for some elements in the first sequence + * and the equals method is specialized. + * + * @see SequencesComparator + * @see EditScript + * + * @since 4.0 + * @version $Id: EditCommand.java 1477760 2013-04-30 18:34:03Z tn $ + */ +public abstract class EditCommand { + + /** Object on which the command should be applied. */ + private final T object; + + /** + * Simple constructor. Creates a new instance of EditCommand + * + * @param object reference to the object associated with this command, this + * refers to an element of one of the sequences being compared + */ + protected EditCommand(final T object) { + this.object = object; + } + + /** + * Returns the object associated with this command. + * + * @return the object on which the command is applied + */ + protected T getObject() { + return object; + } + + /** + * Accept a visitor. + *

              + * This method is invoked for each commands belonging to + * an {@link EditScript EditScript}, in order to implement the visitor design pattern + * + * @param visitor the visitor to be accepted + */ + public abstract void accept(CommandVisitor visitor); + +} diff --git a/src/org/apache/commons/collections4/sequence/EditScript.java b/src/org/apache/commons/collections4/sequence/EditScript.java new file mode 100644 index 0000000..d2e9d5f --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/EditScript.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class gathers all the {@link EditCommand commands} needed to transform + * one objects sequence into another objects sequence. + *

              + * An edit script is the most general view of the differences between two + * sequences. It is built as the result of the comparison between two sequences + * by the {@link SequencesComparator SequencesComparator} class. The user can + * walk through it using the visitor design pattern. + *

              + * It is guaranteed that the objects embedded in the {@link InsertCommand insert + * commands} come from the second sequence and that the objects embedded in + * either the {@link DeleteCommand delete commands} or {@link KeepCommand keep + * commands} come from the first sequence. This can be important if subclassing + * is used for some elements in the first sequence and the equals + * method is specialized. + * + * @see SequencesComparator + * @see EditCommand + * @see CommandVisitor + * @see ReplacementsHandler + * + * @since 4.0 + * @version $Id: EditScript.java 1477760 2013-04-30 18:34:03Z tn $ + */ +public class EditScript { + + /** Container for the commands. */ + private final List> commands; + + /** Length of the longest common subsequence. */ + private int lcsLength; + + /** Number of modifications. */ + private int modifications; + + /** + * Simple constructor. Creates a new empty script. + */ + public EditScript() { + commands = new ArrayList>(); + lcsLength = 0; + modifications = 0; + } + + /** + * Add a keep command to the script. + * + * @param command command to add + */ + public void append(final KeepCommand command) { + commands.add(command); + ++lcsLength; + } + + /** + * Add an insert command to the script. + * + * @param command command to add + */ + public void append(final InsertCommand command) { + commands.add(command); + ++modifications; + } + + /** + * Add a delete command to the script. + * + * @param command command to add + */ + public void append(final DeleteCommand command) { + commands.add(command); + ++modifications; + } + + /** + * Visit the script. The script implements the visitor design + * pattern, this method is the entry point to which the user supplies its + * own visitor, the script will be responsible to drive it through the + * commands in order and call the appropriate method as each command is + * encountered. + * + * @param visitor the visitor that will visit all commands in turn + */ + public void visit(final CommandVisitor visitor) { + for (final EditCommand command : commands) { + command.accept(visitor); + } + } + + /** + * Get the length of the Longest Common Subsequence (LCS). The length of the + * longest common subsequence is the number of {@link KeepCommand keep + * commands} in the script. + * + * @return length of the Longest Common Subsequence + */ + public int getLCSLength() { + return lcsLength; + } + + /** + * Get the number of effective modifications. The number of effective + * modification is the number of {@link DeleteCommand delete} and + * {@link InsertCommand insert} commands in the script. + * + * @return number of effective modifications + */ + public int getModifications() { + return modifications; + } + +} diff --git a/src/org/apache/commons/collections4/sequence/InsertCommand.java b/src/org/apache/commons/collections4/sequence/InsertCommand.java new file mode 100644 index 0000000..47a913f --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/InsertCommand.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +/** + * Command representing the insertion of one object of the second sequence. + *

              + * When one object of the second sequence has no corresponding object in the + * first sequence at the right place, the {@link EditScript edit script} + * transforming the first sequence into the second sequence uses an instance of + * this class to represent the insertion of this object. The objects embedded in + * these type of commands always come from the second sequence. + * + * @see SequencesComparator + * @see EditScript + * + * @since 4.0 + * @version $Id: InsertCommand.java 1477760 2013-04-30 18:34:03Z tn $ + */ +public class InsertCommand extends EditCommand { + + /** + * Simple constructor. Creates a new instance of InsertCommand + * + * @param object the object of the second sequence that should be inserted + */ + public InsertCommand(final T object) { + super(object); + } + + /** + * Accept a visitor. When an InsertCommand accepts a visitor, + * it calls its {@link CommandVisitor#visitInsertCommand visitInsertCommand} + * method. + * + * @param visitor the visitor to be accepted + */ + @Override + public void accept(final CommandVisitor visitor) { + visitor.visitInsertCommand(getObject()); + } + +} diff --git a/src/org/apache/commons/collections4/sequence/KeepCommand.java b/src/org/apache/commons/collections4/sequence/KeepCommand.java new file mode 100644 index 0000000..a0a39a1 --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/KeepCommand.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +/** + * Command representing the keeping of one object present in both sequences. + *

              + * When one object of the first sequence equals another objects in + * the second sequence at the right place, the {@link EditScript edit script} + * transforming the first sequence into the second sequence uses an instance of + * this class to represent the keeping of this object. The objects embedded in + * these type of commands always come from the first sequence. + * + * @see SequencesComparator + * @see EditScript + * + * @since 4.0 + * @version $Id: KeepCommand.java 1477760 2013-04-30 18:34:03Z tn $ + */ +public class KeepCommand extends EditCommand { + + /** + * Simple constructor. Creates a new instance of KeepCommand + * + * @param object the object belonging to both sequences (the object is a + * reference to the instance in the first sequence which is known + * to be equal to an instance in the second sequence) + */ + public KeepCommand(final T object) { + super(object); + } + + /** + * Accept a visitor. When a KeepCommand accepts a visitor, it + * calls its {@link CommandVisitor#visitKeepCommand visitKeepCommand} method. + * + * @param visitor the visitor to be accepted + */ + @Override + public void accept(final CommandVisitor visitor) { + visitor.visitKeepCommand(getObject()); + } +} diff --git a/src/org/apache/commons/collections4/sequence/ReplacementsFinder.java b/src/org/apache/commons/collections4/sequence/ReplacementsFinder.java new file mode 100644 index 0000000..2f9949c --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/ReplacementsFinder.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class handles sequences of replacements resulting from a comparison. + *

              + * The comparison of two objects sequences leads to the identification of common + * parts and parts which only belong to the first or to the second sequence. The + * common parts appear in the edit script in the form of keep commands, + * they can be considered as synchronization objects between the two sequences. + * These synchronization objects split the two sequences in synchronized + * sub-sequences. The first sequence can be transformed into the second one by + * replacing each synchronized sub-sequence of the first sequence by the + * corresponding sub-sequence of the second sequence. This is a synthetic way to + * see an {@link EditScript edit script}, replacing individual + * {@link DeleteCommand delete}, {@link KeepCommand keep} and + * {@link InsertCommand insert} commands by fewer replacements acting on + * complete sub-sequences. + *

              + * This class is devoted to perform this interpretation. It visits an + * {@link EditScript edit script} (because it implements the + * {@link CommandVisitor CommandVisitor} interface) and calls a user-supplied + * handler implementing the {@link ReplacementsHandler ReplacementsHandler} + * interface to process the sub-sequences. + * + * @see ReplacementsHandler + * @see EditScript + * @see SequencesComparator + * + * @since 4.0 + * @version $Id: ReplacementsFinder.java 1477760 2013-04-30 18:34:03Z tn $ + */ +public class ReplacementsFinder implements CommandVisitor { + + private final List pendingInsertions; + private final List pendingDeletions; + private int skipped; + + /** Handler to call when synchronized sequences are found. */ + private final ReplacementsHandler handler; + + /** + * Simple constructor. Creates a new instance of {@link ReplacementsFinder}. + * + * @param handler handler to call when synchronized sequences are found + */ + public ReplacementsFinder(final ReplacementsHandler handler) { + pendingInsertions = new ArrayList(); + pendingDeletions = new ArrayList(); + skipped = 0; + this.handler = handler; + } + + /** + * Add an object to the pending insertions set. + * + * @param object object to insert + */ + public void visitInsertCommand(final T object) { + pendingInsertions.add(object); + } + + /** + * Handle a synchronization object. + *

              + * When a synchronization object is identified, the pending insertions and + * pending deletions sets are provided to the user handler as subsequences. + * + * @param object synchronization object detected + */ + public void visitKeepCommand(final T object) { + if (pendingDeletions.isEmpty() && pendingInsertions.isEmpty()) { + ++skipped; + } else { + handler.handleReplacement(skipped, pendingDeletions, pendingInsertions); + pendingDeletions.clear(); + pendingInsertions.clear(); + skipped = 1; + } + } + + /** + * Add an object to the pending deletions set. + * + * @param object object to delete + */ + public void visitDeleteCommand(final T object) { + pendingDeletions.add(object); + } + +} diff --git a/src/org/apache/commons/collections4/sequence/ReplacementsHandler.java b/src/org/apache/commons/collections4/sequence/ReplacementsHandler.java new file mode 100644 index 0000000..f584a6b --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/ReplacementsHandler.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +import java.util.List; + +/** + * This interface is devoted to handle synchronized replacement sequences. + * + * @see ReplacementsFinder + * @since 4.0 + * @version $Id: ReplacementsHandler.java 1543277 2013-11-19 00:53:50Z ggregory $ + */ +public interface ReplacementsHandler { + + /** + * Handle two synchronized sequences. + *

              + * This method is called by a {@link ReplacementsFinder ReplacementsFinder} + * instance when it has synchronized two sub-sequences of object arrays + * being compared, and at least one of the sequences is non-empty. Since the + * sequences are synchronized, the objects before the two sub-sequences are + * equals (if they exist). This property also holds for the objects after + * the two sub-sequences. + *

              + * The replacement is defined as replacing the from + * sub-sequence into the to sub-sequence. + * + * @param skipped number of tokens skipped since the last call (i.e. number of + * tokens that were in both sequences), this number should be strictly positive + * except on the very first call where it can be zero (if the first object of + * the two sequences are different) + * @param from sub-sequence of objects coming from the first sequence + * @param to sub-sequence of objects coming from the second sequence + */ + void handleReplacement(int skipped, List from, List to); + +} diff --git a/src/org/apache/commons/collections4/sequence/SequencesComparator.java b/src/org/apache/commons/collections4/sequence/SequencesComparator.java new file mode 100644 index 0000000..dd57c0a --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/SequencesComparator.java @@ -0,0 +1,348 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.sequence; + +import java.util.List; + +import org.apache.commons.collections4.Equator; +import org.apache.commons.collections4.functors.DefaultEquator; + +/** + * This class allows to compare two objects sequences. + *

              + * The two sequences can hold any object type, as only the equals + * method is used to compare the elements of the sequences. It is guaranteed + * that the comparisons will always be done as o1.equals(o2) where + * o1 belongs to the first sequence and o2 belongs to + * the second sequence. This can be important if subclassing is used for some + * elements in the first sequence and the equals method is + * specialized. + *

              + * Comparison can be seen from two points of view: either as giving the smallest + * modification allowing to transform the first sequence into the second one, or + * as giving the longest sequence which is a subsequence of both initial + * sequences. The equals method is used to compare objects, so any + * object can be put into sequences. Modifications include deleting, inserting + * or keeping one object, starting from the beginning of the first sequence. + *

              + * This class implements the comparison algorithm, which is the very efficient + * algorithm from Eugene W. Myers + * + * An O(ND) Difference Algorithm and Its Variations. This algorithm produces + * the shortest possible + * {@link EditScript edit script} + * containing all the + * {@link EditCommand commands} + * needed to transform the first sequence into the second one. + * + * @see EditScript + * @see EditCommand + * @see CommandVisitor + * + * @since 4.0 + * @version $Id: SequencesComparator.java 1540567 2013-11-10 22:19:29Z tn $ + */ +public class SequencesComparator { + + /** First sequence. */ + private final List sequence1; + + /** Second sequence. */ + private final List sequence2; + + /** The equator used for testing object equality. */ + private final Equator equator; + + /** Temporary variables. */ + private final int[] vDown; + private final int[] vUp; + + /** + * Simple constructor. + *

              + * Creates a new instance of SequencesComparator using a {@link DefaultEquator}. + *

              + * It is guaranteed that the comparisons will always be done as + * o1.equals(o2) where o1 belongs to the first + * sequence and o2 belongs to the second sequence. This can be + * important if subclassing is used for some elements in the first sequence + * and the equals method is specialized. + * + * @param sequence1 first sequence to be compared + * @param sequence2 second sequence to be compared + */ + public SequencesComparator(final List sequence1, final List sequence2) { + this(sequence1, sequence2, DefaultEquator.defaultEquator()); + } + + /** + * Simple constructor. + *

              + * Creates a new instance of SequencesComparator with a custom {@link Equator}. + *

              + * It is guaranteed that the comparisons will always be done as + * Equator.equate(o1, o2) where o1 belongs to the first + * sequence and o2 belongs to the second sequence. + * + * @param sequence1 first sequence to be compared + * @param sequence2 second sequence to be compared + * @param equator the equator to use for testing object equality + */ + public SequencesComparator(final List sequence1, final List sequence2, final Equator equator) { + this.sequence1 = sequence1; + this.sequence2 = sequence2; + this.equator = equator; + + final int size = sequence1.size() + sequence2.size() + 2; + vDown = new int[size]; + vUp = new int[size]; + } + + /** + * Get the {@link EditScript} object. + *

              + * It is guaranteed that the objects embedded in the {@link InsertCommand + * insert commands} come from the second sequence and that the objects + * embedded in either the {@link DeleteCommand delete commands} or + * {@link KeepCommand keep commands} come from the first sequence. This can + * be important if subclassing is used for some elements in the first + * sequence and the equals method is specialized. + * + * @return the edit script resulting from the comparison of the two + * sequences + */ + public EditScript getScript() { + final EditScript script = new EditScript(); + buildScript(0, sequence1.size(), 0, sequence2.size(), script); + return script; + } + + /** + * Build a snake. + * + * @param start the value of the start of the snake + * @param diag the value of the diagonal of the snake + * @param end1 the value of the end of the first sequence to be compared + * @param end2 the value of the end of the second sequence to be compared + * @return the snake built + */ + private Snake buildSnake(final int start, final int diag, final int end1, final int end2) { + int end = start; + while (end - diag < end2 + && end < end1 + && equator.equate(sequence1.get(end), sequence2.get(end - diag))) { + ++end; + } + return new Snake(start, end, diag); + } + + /** + * Get the middle snake corresponding to two subsequences of the + * main sequences. + *

              + * The snake is found using the MYERS Algorithm (this algorithms has + * also been implemented in the GNU diff program). This algorithm is + * explained in Eugene Myers article: + * + * An O(ND) Difference Algorithm and Its Variations. + * + * @param start1 the begin of the first sequence to be compared + * @param end1 the end of the first sequence to be compared + * @param start2 the begin of the second sequence to be compared + * @param end2 the end of the second sequence to be compared + * @return the middle snake + */ + private Snake getMiddleSnake(final int start1, final int end1, final int start2, final int end2) { + // Myers Algorithm + // Initialisations + final int m = end1 - start1; + final int n = end2 - start2; + if (m == 0 || n == 0) { + return null; + } + + final int delta = m - n; + final int sum = n + m; + final int offset = (sum % 2 == 0 ? sum : sum + 1) / 2; + vDown[1+offset] = start1; + vUp[1+offset] = end1 + 1; + + for (int d = 0; d <= offset ; ++d) { + // Down + for (int k = -d; k <= d; k += 2) { + // First step + + final int i = k + offset; + if (k == -d || k != d && vDown[i-1] < vDown[i+1]) { + vDown[i] = vDown[i+1]; + } else { + vDown[i] = vDown[i-1] + 1; + } + + int x = vDown[i]; + int y = x - start1 + start2 - k; + + while (x < end1 && y < end2 && equator.equate(sequence1.get(x), sequence2.get(y))) { + vDown[i] = ++x; + ++y; + } + // Second step + if (delta % 2 != 0 && delta - d <= k && k <= delta + d) { + if (vUp[i-delta] <= vDown[i]) { + return buildSnake(vUp[i-delta], k + start1 - start2, end1, end2); + } + } + } + + // Up + for (int k = delta - d; k <= delta + d; k += 2) { + // First step + final int i = k + offset - delta; + if (k == delta - d + || k != delta + d && vUp[i+1] <= vUp[i-1]) { + vUp[i] = vUp[i+1] - 1; + } else { + vUp[i] = vUp[i-1]; + } + + int x = vUp[i] - 1; + int y = x - start1 + start2 - k; + while (x >= start1 && y >= start2 + && equator.equate(sequence1.get(x), sequence2.get(y))) { + vUp[i] = x--; + y--; + } + // Second step + if (delta % 2 == 0 && -d <= k && k <= d ) { + if (vUp[i] <= vDown[i + delta]) { + return buildSnake(vUp[i], k + start1 - start2, end1, end2); + } + } + } + } + + // this should not happen + throw new RuntimeException("Internal Error"); + } + + + /** + * Build an edit script. + * + * @param start1 the begin of the first sequence to be compared + * @param end1 the end of the first sequence to be compared + * @param start2 the begin of the second sequence to be compared + * @param end2 the end of the second sequence to be compared + * @param script the edited script + */ + private void buildScript(final int start1, final int end1, final int start2, final int end2, + final EditScript script) { + + final Snake middle = getMiddleSnake(start1, end1, start2, end2); + + if (middle == null + || middle.getStart() == end1 && middle.getDiag() == end1 - end2 + || middle.getEnd() == start1 && middle.getDiag() == start1 - start2) { + + int i = start1; + int j = start2; + while (i < end1 || j < end2) { + if (i < end1 && j < end2 && equator.equate(sequence1.get(i), sequence2.get(j))) { + script.append(new KeepCommand(sequence1.get(i))); + ++i; + ++j; + } else { + if (end1 - start1 > end2 - start2) { + script.append(new DeleteCommand(sequence1.get(i))); + ++i; + } else { + script.append(new InsertCommand(sequence2.get(j))); + ++j; + } + } + } + + } else { + + buildScript(start1, middle.getStart(), + start2, middle.getStart() - middle.getDiag(), + script); + for (int i = middle.getStart(); i < middle.getEnd(); ++i) { + script.append(new KeepCommand(sequence1.get(i))); + } + buildScript(middle.getEnd(), end1, + middle.getEnd() - middle.getDiag(), end2, + script); + } + } + + /** + * This class is a simple placeholder to hold the end part of a path + * under construction in a {@link SequencesComparator SequencesComparator}. + */ + private static class Snake { + + /** Start index. */ + private final int start; + + /** End index. */ + private final int end; + + /** Diagonal number. */ + private final int diag; + + /** + * Simple constructor. Creates a new instance of Snake with specified indices. + * + * @param start start index of the snake + * @param end end index of the snake + * @param diag diagonal number + */ + public Snake(final int start, final int end, final int diag) { + this.start = start; + this.end = end; + this.diag = diag; + } + + /** + * Get the start index of the snake. + * + * @return start index of the snake + */ + public int getStart() { + return start; + } + + /** + * Get the end index of the snake. + * + * @return end index of the snake + */ + public int getEnd() { + return end; + } + + /** + * Get the diagonal number of the snake. + * + * @return diagonal number of the snake + */ + public int getDiag() { + return diag; + } + } +} diff --git a/src/org/apache/commons/collections4/sequence/package-info.java b/src/org/apache/commons/collections4/sequence/package-info.java new file mode 100644 index 0000000..42011eb --- /dev/null +++ b/src/org/apache/commons/collections4/sequence/package-info.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package provides classes to compare two sequences of objects. + *

              + * The two sequences can hold any object type, as only the + * equals method is used to compare the elements of the + * sequences. It is guaranteed that the comparisons will always be done + * as o1.equals(o2) where o1 belongs to the + * first sequence and o2 belongs to the second + * sequence. This can be important if subclassing is used for some + * elements in the first sequence and the equals method is + * specialized. + *

              + * Comparison can be seen from two points of view: either as giving the + * smallest modification allowing to transform the first sequence into + * the second one, or as giving the longest sequence which is a + * subsequence of both initial sequences. The equals method + * is used to compare objects, so any object can be put into + * sequences. Modifications include deleting, inserting or keeping one + * object, starting from the beginning of the first sequence. Like most + * algorithms of the same type, objects transpositions are not + * supported. This means that if a sequence (A, B) is + * compared to (B, A), the result will be either the + * sequence of three commands delete A, keep B, + * insert A or the sequence insert B, + * keep A, delete B. + *

              + * The package uses a very efficient comparison algorithm designed by + * Eugene W. Myers and described in his paper: An O(ND) + * Difference Algorithm and Its Variations. This algorithm produces + * the shortest possible + * {@link org.apache.commons.collections4.sequence.EditScript edit script} containing + * all the {@link org.apache.commons.collections4.sequence.EditCommand commands} + * needed to transform the first sequence into the second one. + * The entry point for the user to this algorithm is the + * {@link org.apache.commons.collections4.sequence.SequencesComparator} class. + *

              + * As explained in Gene Myers paper, the edit script is equivalent to all + * other representations and contains all the needed information either + * to perform the transformation, of course, or to retrieve the longest + * common subsequence for example. + *

              + * If the user needs a very fine grained access to the comparison result, + * he needs to go through this script by providing a visitor implementing + * the {@link org.apache.commons.collections4.sequence.CommandVisitor} interface. + *

              + * Sometimes however, a more synthetic approach is needed. If the user + * prefers to see the differences between the two sequences as global + * replacement operations acting on complete subsequences of + * the original sequences, he will provide an object implementing the + * simple {@link org.apache.commons.collections4.sequence.ReplacementsHandler} interface, + * using an instance of the {@link org.apache.commons.collections4.sequence.ReplacementsFinder} + * class as a command converting layer between his object and the edit script. The number of + * objects which are common to both initial arrays and hence are skipped between each call to the user + * {@link org.apache.commons.collections4.sequence.ReplacementsHandler#handleReplacement handleReplacement} + * method is also provided. This allows the user to keep track of the current index in + * both arrays if he needs so. + * + * @version $Id: package-info.java 1479338 2013-05-05 15:21:44Z tn $ + */ +package org.apache.commons.collections4.sequence; diff --git a/src/org/apache/commons/collections4/set/AbstractNavigableSetDecorator.java b/src/org/apache/commons/collections4/set/AbstractNavigableSetDecorator.java new file mode 100644 index 0000000..3b4afac --- /dev/null +++ b/src/org/apache/commons/collections4/set/AbstractNavigableSetDecorator.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Iterator; +import java.util.NavigableSet; + +/** + * Decorates another NavigableSet to provide additional behaviour. + *

              + * Methods are forwarded directly to the decorated set. + * + * @param the type of the elements in the navigable set + * @since 4.1 + * @version $Id: AbstractNavigableSetDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractNavigableSetDecorator + extends AbstractSortedSetDecorator + implements NavigableSet { + + /** Serialization version */ + private static final long serialVersionUID = 20150528L; + + /** + * Constructor only used in deserialization, do not use otherwise. + */ + protected AbstractNavigableSetDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws NullPointerException if set is null + */ + protected AbstractNavigableSetDecorator(final NavigableSet set) { + super(set); + } + + /** + * Gets the set being decorated. + * + * @return the decorated set + */ + @Override + protected NavigableSet decorated() { + return (NavigableSet) super.decorated(); + } + + //----------------------------------------------------------------------- + + @Override + public E lower(E e) { + return decorated().lower(e); + } + + @Override + public E floor(E e) { + return decorated().floor(e); + } + + @Override + public E ceiling(E e) { + return decorated().ceiling(e); + } + + @Override + public E higher(E e) { + return decorated().higher(e); + } + + @Override + public E pollFirst() { + return decorated().pollFirst(); + } + + @Override + public E pollLast() { + return decorated().pollLast(); + } + + @Override + public NavigableSet descendingSet() { + return decorated().descendingSet(); + } + + @Override + public Iterator descendingIterator() { + return decorated().descendingIterator(); + } + + @Override + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + return decorated().subSet(fromElement, fromInclusive, toElement, toInclusive); + } + + @Override + public NavigableSet headSet(E toElement, boolean inclusive) { + return decorated().headSet(toElement, inclusive); + } + + @Override + public NavigableSet tailSet(E fromElement, boolean inclusive) { + return decorated().tailSet(fromElement, inclusive); + } + +} diff --git a/src/org/apache/commons/collections4/set/AbstractSerializableSetDecorator.java b/src/org/apache/commons/collections4/set/AbstractSerializableSetDecorator.java new file mode 100644 index 0000000..312f9b4 --- /dev/null +++ b/src/org/apache/commons/collections4/set/AbstractSerializableSetDecorator.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Set; + +/** + * Serializable subclass of AbstractSetDecorator. + * + * @since 3.1 + * @version $Id: AbstractSerializableSetDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractSerializableSetDecorator + extends AbstractSetDecorator { + + /** Serialization version */ + private static final long serialVersionUID = 1229469966212206107L; + + /** + * Constructor. + * + * @param set the list to decorate, must not be null + * @throws NullPointerException if set is null + */ + protected AbstractSerializableSetDecorator(final Set set) { + super(set); + } + + //----------------------------------------------------------------------- + /** + * Write the set out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the set in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); + } + +} diff --git a/src/org/apache/commons/collections4/set/AbstractSetDecorator.java b/src/org/apache/commons/collections4/set/AbstractSetDecorator.java new file mode 100644 index 0000000..8c6358e --- /dev/null +++ b/src/org/apache/commons/collections4/set/AbstractSetDecorator.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Set; + +import org.apache.commons.collections4.collection.AbstractCollectionDecorator; + +/** + * Decorates another Set to provide additional behaviour. + *

              + * Methods are forwarded directly to the decorated set. + * + * @param the type of the elements in the set + * @since 3.0 + * @version $Id: AbstractSetDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractSetDecorator extends AbstractCollectionDecorator implements + Set { + + /** Serialization version */ + private static final long serialVersionUID = -4678668309576958546L; + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractSetDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws NullPointerException if set is null + */ + protected AbstractSetDecorator(final Set set) { + super(set); + } + + /** + * Gets the set being decorated. + * + * @return the decorated set + */ + @Override + protected Set decorated() { + return (Set) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + +} diff --git a/src/org/apache/commons/collections4/set/AbstractSortedSetDecorator.java b/src/org/apache/commons/collections4/set/AbstractSortedSetDecorator.java new file mode 100644 index 0000000..3740e12 --- /dev/null +++ b/src/org/apache/commons/collections4/set/AbstractSortedSetDecorator.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Comparator; +import java.util.Set; +import java.util.SortedSet; + +/** + * Decorates another SortedSet to provide additional behaviour. + *

              + * Methods are forwarded directly to the decorated set. + * + * @param the type of the elements in the sorted set + * @since 3.0 + * @version $Id: AbstractSortedSetDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public abstract class AbstractSortedSetDecorator + extends AbstractSetDecorator + implements SortedSet { + + /** Serialization version */ + private static final long serialVersionUID = -3462240946294214398L; + + /** + * Constructor only used in deserialization, do not use otherwise. + * @since 3.1 + */ + protected AbstractSortedSetDecorator() { + super(); + } + + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws NullPointerException if set is null + */ + protected AbstractSortedSetDecorator(final Set set) { + super(set); + } + + /** + * Gets the set being decorated. + * + * @return the decorated set + */ + @Override + protected SortedSet decorated() { + return (SortedSet) super.decorated(); + } + + //----------------------------------------------------------------------- + public SortedSet subSet(final E fromElement, final E toElement) { + return decorated().subSet(fromElement, toElement); + } + + public SortedSet headSet(final E toElement) { + return decorated().headSet(toElement); + } + + public SortedSet tailSet(final E fromElement) { + return decorated().tailSet(fromElement); + } + + public E first() { + return decorated().first(); + } + + public E last() { + return decorated().last(); + } + + public Comparator comparator() { + return decorated().comparator(); + } + +} diff --git a/src/org/apache/commons/collections4/set/CompositeSet.java b/src/org/apache/commons/collections4/set/CompositeSet.java new file mode 100644 index 0000000..16ba07b --- /dev/null +++ b/src/org/apache/commons/collections4/set/CompositeSet.java @@ -0,0 +1,500 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.iterators.EmptyIterator; +import org.apache.commons.collections4.iterators.IteratorChain; +import org.apache.commons.collections4.list.UnmodifiableList; + +/** + * Decorates a set of other sets to provide a single unified view. + *

              + * Changes made to this set will actually be made on the decorated set. + * Add operations require the use of a pluggable strategy. + * If no strategy is provided then add is unsupported. + *

              + * From version 4.0, this class does not extend + * {@link org.apache.commons.collections4.collection.CompositeCollection CompositeCollection} + * anymore due to its input restrictions (only accepts Sets). + * See COLLECTIONS-424 + * for more details. + * + * @since 3.0 + * @version $Id: CompositeSet.java 1543273 2013-11-19 00:52:40Z ggregory $ + */ +public class CompositeSet implements Set, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 5185069727540378940L; + + /** SetMutator to handle changes to the collection */ + private SetMutator mutator; + + /** Sets in the composite */ + private final List> all = new ArrayList>(); + + /** + * Create an empty CompositeSet. + */ + public CompositeSet() { + super(); + } + + /** + * Create a CompositeSet with just set composited. + * + * @param set the initial set in the composite + */ + public CompositeSet(final Set set) { + super(); + addComposited(set); + } + + /** + * Create a composite set with sets as the initial set of composited Sets. + * + * @param sets the initial sets in the composite + */ + @SafeVarargs + public CompositeSet(final Set... sets) { + super(); + addComposited(sets); + } + + //----------------------------------------------------------------------- + /** + * Gets the size of this composite set. + *

              + * This implementation calls size() on each set. + * + * @return total number of elements in all contained containers + */ + public int size() { + int size = 0; + for (final Set item : all) { + size += item.size(); + } + return size; + } + + /** + * Checks whether this composite set is empty. + *

              + * This implementation calls isEmpty() on each set. + * + * @return true if all of the contained sets are empty + */ + public boolean isEmpty() { + for (final Set item : all) { + if (item.isEmpty() == false) { + return false; + } + } + return true; + } + + /** + * Checks whether this composite set contains the object. + *

              + * This implementation calls contains() on each set. + * + * @param obj the object to search for + * @return true if obj is contained in any of the contained sets + */ + public boolean contains(final Object obj) { + for (final Set item : all) { + if (item.contains(obj)) { + return true; + } + } + return false; + } + + /** + * Gets an iterator over all the sets in this composite. + *

              + * This implementation uses an IteratorChain. + * + * @return an IteratorChain instance which supports + * remove(). Iteration occurs over contained collections in + * the order they were added, but this behavior should not be relied upon. + * @see IteratorChain + */ + public Iterator iterator() { + if (all.isEmpty()) { + return EmptyIterator.emptyIterator(); + } + final IteratorChain chain = new IteratorChain(); + for (final Set item : all) { + chain.addIterator(item.iterator()); + } + return chain; + } + + /** + * Returns an array containing all of the elements in this composite. + * + * @return an object array of all the elements in the collection + */ + public Object[] toArray() { + final Object[] result = new Object[size()]; + int i = 0; + for (final Iterator it = iterator(); it.hasNext(); i++) { + result[i] = it.next(); + } + return result; + } + + /** + * Returns an object array, populating the supplied array if possible. + * See Collection interface for full details. + * + * @param the type of the elements in the collection + * @param array the array to use, populating if possible + * @return an array of all the elements in the collection + */ + @SuppressWarnings("unchecked") + public T[] toArray(final T[] array) { + final int size = size(); + Object[] result = null; + if (array.length >= size) { + result = array; + } else { + result = (Object[]) Array.newInstance(array.getClass().getComponentType(), size); + } + + int offset = 0; + for (final Collection item : all) { + for (final E e : item) { + result[offset++] = e; + } + } + if (result.length > size) { + result[size] = null; + } + return (T[]) result; + } + + /** + * Adds an object to the collection, throwing UnsupportedOperationException + * unless a SetMutator strategy is specified. + * + * @param obj the object to add + * @return {@code true} if the collection was modified + * @throws UnsupportedOperationException if SetMutator hasn't been set or add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + public boolean add(final E obj) { + if (mutator == null) { + throw new UnsupportedOperationException( + "add() is not supported on CompositeSet without a SetMutator strategy"); + } + return mutator.add(this, all, obj); + } + + /** + * If a CollectionMutator is defined for this CompositeSet then this + * method will be called anyway. + * + * @param obj object to be removed + * @return true if the object is removed, false otherwise + */ + public boolean remove(final Object obj) { + for (final Set set : getSets()) { + if (set.contains(obj)) { + return set.remove(obj); + } + } + return false; + } + + /** + * Checks whether this composite contains all the elements in the specified collection. + *

              + * This implementation calls contains() for each element in the + * specified collection. + * + * @param coll the collection to check for + * @return true if all elements contained + */ + public boolean containsAll(final Collection coll) { + for (final Object item : coll) { + if (contains(item) == false) { + return false; + } + } + return true; + } + + /** + * Adds a collection of elements to this composite, throwing + * UnsupportedOperationException unless a SetMutator strategy is specified. + * + * @param coll the collection to add + * @return true if the composite was modified + * @throws UnsupportedOperationException if SetMutator hasn't been set or add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + public boolean addAll(final Collection coll) { + if (mutator == null) { + throw new UnsupportedOperationException( + "addAll() is not supported on CompositeSet without a SetMutator strategy"); + } + return mutator.addAll(this, all, coll); + } + + /** + * Removes the elements in the specified collection from this composite set. + *

              + * This implementation calls removeAll on each collection. + * + * @param coll the collection to remove + * @return true if the composite was modified + * @throws UnsupportedOperationException if removeAll is unsupported + */ + public boolean removeAll(final Collection coll) { + if (coll.size() == 0) { + return false; + } + boolean changed = false; + for (final Collection item : all) { + changed |= item.removeAll(coll); + } + return changed; + } + + /** + * Retains all the elements in the specified collection in this composite set, + * removing all others. + *

              + * This implementation calls retainAll() on each collection. + * + * @param coll the collection to remove + * @return true if the composite was modified + * @throws UnsupportedOperationException if retainAll is unsupported + */ + public boolean retainAll(final Collection coll) { + boolean changed = false; + for (final Collection item : all) { + changed |= item.retainAll(coll); + } + return changed; + } + + /** + * Removes all of the elements from this composite set. + *

              + * This implementation calls clear() on each set. + * + * @throws UnsupportedOperationException if clear is unsupported + */ + public void clear() { + for (final Collection coll : all) { + coll.clear(); + } + } + + //----------------------------------------------------------------------- + /** + * Specify a SetMutator strategy instance to handle changes. + * + * @param mutator the mutator to use + */ + public void setMutator(final SetMutator mutator) { + this.mutator = mutator; + } + + /** + * Add a Set to this composite. + * + * @param set the set to add + * @throws IllegalArgumentException if a SetMutator is set, but fails to resolve a collision + * @throws UnsupportedOperationException if there is no SetMutator set + * @throws NullPointerException if {@code set} is null + * @see SetMutator + */ + public synchronized void addComposited(final Set set) { + for (final Set existingSet : getSets()) { + final Collection intersects = CollectionUtils.intersection(existingSet, set); + if (intersects.size() > 0) { + if (this.mutator == null) { + throw new UnsupportedOperationException( + "Collision adding composited set with no SetMutator set"); + } + getMutator().resolveCollision(this, existingSet, set, intersects); + if (CollectionUtils.intersection(existingSet, set).size() > 0) { + throw new IllegalArgumentException( + "Attempt to add illegal entry unresolved by SetMutator.resolveCollision()"); + } + } + } + all.add(set); + } + + /** + * Add these Sets to the list of sets in this composite. + * + * @param set1 the first Set to be appended to the composite + * @param set2 the second Set to be appended to the composite + */ + public void addComposited(final Set set1, final Set set2) { + addComposited(set1); + addComposited(set2); + } + + /** + * Add these Sets to the list of sets in this composite + * + * @param sets the Sets to be appended to the composite + */ + @SuppressWarnings("unchecked") + public void addComposited(final Set... sets) { + for (Set set : sets) { + addComposited(set); + } + } + + /** + * Removes a set from those being decorated in this composite. + * + * @param set set to be removed + */ + public void removeComposited(final Set set) { + all.remove(set); + } + + //----------------------------------------------------------------------- + /** + * Returns a new Set containing all of the elements. + * + * @return A new HashSet containing all of the elements in this composite. + * The new collection is not backed by this composite. + */ + public Set toSet() { + return new HashSet(this); + } + + /** + * Gets the sets being decorated. + * + * @return Unmodifiable list of all sets in this composite. + */ + public List> getSets() { + return UnmodifiableList.unmodifiableList(all); + } + + /** + * Get the set mutator to be used for this CompositeSet. + * @return the set mutator + */ + protected SetMutator getMutator() { + return mutator; + } + + /** + * {@inheritDoc} + * @see java.util.Set#equals + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof Set) { + final Set set = (Set) obj; + return set.size() == this.size() && set.containsAll(this); + } + return false; + } + + /** + * {@inheritDoc} + * @see java.util.Set#hashCode + */ + @Override + public int hashCode() { + int code = 0; + for (final E e : this) { + code += e == null ? 0 : e.hashCode(); + } + return code; + } + + /** + * Define callbacks for mutation operations. + */ + public static interface SetMutator extends Serializable { + + /** + * Called when an object is to be added to the composite. + * + * @param composite the CompositeSet being changed + * @param sets all of the Set instances in this CompositeSet + * @param obj the object being added + * @return true if the collection is changed + * @throws UnsupportedOperationException if add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + boolean add(CompositeSet composite, List> sets, E obj); + + /** + * Called when a collection is to be added to the composite. + * + * @param composite the CompositeSet being changed + * @param sets all of the Set instances in this CompositeSet + * @param coll the collection being added + * @return true if the collection is changed + * @throws UnsupportedOperationException if add is unsupported + * @throws ClassCastException if the object cannot be added due to its type + * @throws NullPointerException if the object cannot be added because its null + * @throws IllegalArgumentException if the object cannot be added + */ + boolean addAll(CompositeSet composite, + List> sets, + Collection coll); + + /** + * Called when a Set is added to the CompositeSet and there is a + * collision between existing and added sets. + *

              + * If added and existing still have any intersects + * after this method returns an IllegalArgumentException will be thrown. + * + * @param comp the CompositeSet being modified + * @param existing the Set already existing in the composite + * @param added the Set being added to the composite + * @param intersects the intersection of the existing and added sets + */ + void resolveCollision(CompositeSet comp, + Set existing, + Set added, + Collection intersects); + } +} diff --git a/src/org/apache/commons/collections4/set/ListOrderedSet.java b/src/org/apache/commons/collections4/set/ListOrderedSet.java new file mode 100644 index 0000000..6ec35c7 --- /dev/null +++ b/src/org/apache/commons/collections4/set/ListOrderedSet.java @@ -0,0 +1,409 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.OrderedIterator; +import org.apache.commons.collections4.functors.UniquePredicate; +import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; +import org.apache.commons.collections4.list.UnmodifiableList; + +/** + * Decorates another Set to ensure that the order of addition is + * retained and used by the iterator. + *

              + * If an object is added to the set for a second time, it will remain in the + * original position in the iteration. The order can be observed from the set + * via the iterator or toArray methods. + *

              + * The ListOrderedSet also has various useful direct methods. These include many + * from List, such as get(int), + * remove(int) and indexOf(int). An unmodifiable + * List view of the set can be obtained via asList(). + *

              + * This class cannot implement the List interface directly as + * various interface methods (notably equals/hashCode) are incompatible with a + * set. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: ListOrderedSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class ListOrderedSet + extends AbstractSerializableSetDecorator { + + /** Serialization version */ + private static final long serialVersionUID = -228664372470420141L; + + /** Internal list to hold the sequence of objects */ + private final List setOrder; + + /** + * Factory method to create an ordered set specifying the list and set to use. + *

              + * The list and set must both be empty. + * + * @param the element type + * @param set the set to decorate, must be empty and not null + * @param list the list to decorate, must be empty and not null + * @return a new ordered set + * @throws NullPointerException if set or list is null + * @throws IllegalArgumentException if either the set or list is not empty + * @since 4.0 + */ + public static ListOrderedSet listOrderedSet(final Set set, final List list) { + if (set == null) { + throw new NullPointerException("Set must not be null"); + } + if (list == null) { + throw new NullPointerException("List must not be null"); + } + if (set.size() > 0 || list.size() > 0) { + throw new IllegalArgumentException("Set and List must be empty"); + } + return new ListOrderedSet(set, list); + } + + /** + * Factory method to create an ordered set. + *

              + * An ArrayList is used to retain order. + * + * @param the element type + * @param set the set to decorate, must not be null + * @return a new ordered set + * @throws NullPointerException if set is null + * @since 4.0 + */ + public static ListOrderedSet listOrderedSet(final Set set) { + return new ListOrderedSet(set); + } + + /** + * Factory method to create an ordered set using the supplied list to retain order. + *

              + * A HashSet is used for the set behaviour. + *

              + * NOTE: If the list contains duplicates, the duplicates are removed, + * altering the specified list. + * + * @param the element type + * @param list the list to decorate, must not be null + * @return a new ordered set + * @throws NullPointerException if list is null + * @since 4.0 + */ + public static ListOrderedSet listOrderedSet(final List list) { + if (list == null) { + throw new NullPointerException("List must not be null"); + } + CollectionUtils.filter(list, UniquePredicate.uniquePredicate()); + final Set set = new HashSet(list); + + return new ListOrderedSet(set, list); + } + + // ----------------------------------------------------------------------- + /** + * Constructs a new empty ListOrderedSet using a + * HashSet and an ArrayList internally. + * + * @since 3.1 + */ + public ListOrderedSet() { + super(new HashSet()); + setOrder = new ArrayList(); + } + + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws IllegalArgumentException if set is null + */ + protected ListOrderedSet(final Set set) { + super(set); + setOrder = new ArrayList(set); + } + + /** + * Constructor that wraps (not copies) the Set and specifies the list to + * use. + *

              + * The set and list must both be correctly initialised to the same elements. + * + * @param set the set to decorate, must not be null + * @param list the list to decorate, must not be null + * @throws NullPointerException if set or list is null + */ + protected ListOrderedSet(final Set set, final List list) { + super(set); + if (list == null) { + throw new NullPointerException("List must not be null"); + } + setOrder = list; + } + + // ----------------------------------------------------------------------- + /** + * Gets an unmodifiable view of the order of the Set. + * + * @return an unmodifiable list view + */ + public List asList() { + return UnmodifiableList.unmodifiableList(setOrder); + } + + // ----------------------------------------------------------------------- + @Override + public void clear() { + decorated().clear(); + setOrder.clear(); + } + + @Override + public OrderedIterator iterator() { + return new OrderedSetIterator(setOrder.listIterator(), decorated()); + } + + @Override + public boolean add(final E object) { + if (decorated().add(object)) { + setOrder.add(object); + return true; + } + return false; + } + + @Override + public boolean addAll(final Collection coll) { + boolean result = false; + for (final E e : coll) { + result |= add(e); + } + return result; + } + + @Override + public boolean remove(final Object object) { + final boolean result = decorated().remove(object); + if (result) { + setOrder.remove(object); + } + return result; + } + + @Override + public boolean removeAll(final Collection coll) { + boolean result = false; + for (final Object name : coll) { + result |= remove(name); + } + return result; + } + + /** + * {@inheritDoc} + *

              + * This implementation iterates over the elements of this set, checking + * each element in turn to see if it's contained in coll. + * If it's not contained, it's removed from this set. As a consequence, + * it is advised to use a collection type for coll that provides + * a fast (e.g. O(1)) implementation of {@link Collection#contains(Object)}. + */ + @Override + public boolean retainAll(final Collection coll) { + boolean result = decorated().retainAll(coll); + if (result == false) { + return false; + } + if (decorated().size() == 0) { + setOrder.clear(); + } else { + for (Iterator it = setOrder.iterator(); it.hasNext();) { + if (!decorated().contains(it.next())) { + it.remove(); + } + } + } + return result; + } + + @Override + public Object[] toArray() { + return setOrder.toArray(); + } + + @Override + public T[] toArray(final T a[]) { + return setOrder.toArray(a); + } + + // ----------------------------------------------------------------------- + // Additional methods that comply to the {@link List} interface + // ----------------------------------------------------------------------- + + /** + * Returns the element at the specified position in this ordered set. + * + * @param index the position of the element in the ordered {@link Set}. + * @return the element at position {@code index} + * @see List#get(int) + */ + public E get(final int index) { + return setOrder.get(index); + } + + /** + * Returns the index of the first occurrence of the specified element in + * ordered set. + * + * @param object the element to search for + * @return the index of the first occurrence of the object, or {@code -1} if + * this ordered set does not contain this object + * @see List#indexOf(Object) + */ + public int indexOf(final Object object) { + return setOrder.indexOf(object); + } + + /** + * Inserts the specified element at the specified position if it is not yet + * contained in this ordered set (optional operation). Shifts the element + * currently at this position and any subsequent elements to the right. + * + * @param index the index at which the element is to be inserted + * @param object the element to be inserted + * @see List#add(int, Object) + */ + public void add(final int index, final E object) { + if (!contains(object)) { + decorated().add(object); + setOrder.add(index, object); + } + } + + /** + * Inserts all elements in the specified collection not yet contained in the + * ordered set at the specified position (optional operation). Shifts the + * element currently at the position and all subsequent elements to the + * right. + * + * @param index the position to insert the elements + * @param coll the collection containing the elements to be inserted + * @return {@code true} if this ordered set changed as a result of the call + * @see List#addAll(int, Collection) + */ + public boolean addAll(final int index, final Collection coll) { + boolean changed = false; + // collect all elements to be added for performance reasons + final List toAdd = new ArrayList(); + for (final E e : coll) { + if (contains(e)) { + continue; + } + decorated().add(e); + toAdd.add(e); + changed = true; + } + + if (changed) { + setOrder.addAll(index, toAdd); + } + + return changed; + } + + /** + * Removes the element at the specified position from the ordered set. + * Shifts any subsequent elements to the left. + * + * @param index the index of the element to be removed + * @return the element that has been remove from the ordered set + * @see List#remove(int) + */ + public E remove(final int index) { + final E obj = setOrder.remove(index); + remove(obj); + return obj; + } + + /** + * Uses the underlying List's toString so that order is achieved. This means + * that the decorated Set's toString is not used, so any custom toStrings + * will be ignored. + * + * @return a string representation of the ordered set + */ + // Fortunately List.toString and Set.toString look the same + @Override + public String toString() { + return setOrder.toString(); + } + + // ----------------------------------------------------------------------- + /** + * Internal iterator handle remove. + */ + static class OrderedSetIterator + extends AbstractIteratorDecorator + implements OrderedIterator { + + /** Object we iterate on */ + private final Collection set; + + /** Last object retrieved */ + private E last; + + private OrderedSetIterator(final ListIterator iterator, final Collection set) { + super(iterator); + this.set = set; + } + + @Override + public E next() { + last = getIterator().next(); + return last; + } + + @Override + public void remove() { + set.remove(last); + getIterator().remove(); + last = null; + } + + public boolean hasPrevious() { + return ((ListIterator) getIterator()).hasPrevious(); + } + + public E previous() { + last = ((ListIterator) getIterator()).previous(); + return last; + } + } + +} diff --git a/src/org/apache/commons/collections4/set/MapBackedSet.java b/src/org/apache/commons/collections4/set/MapBackedSet.java new file mode 100644 index 0000000..399d3a3 --- /dev/null +++ b/src/org/apache/commons/collections4/set/MapBackedSet.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * Decorates a Map to obtain Set behaviour. + *

              + * This class is used to create a Set with the same properties as + * the key set of any map. Thus, a ReferenceSet can be created by wrapping a + * ReferenceMap in an instance of this class. + *

              + * Most map implementation can be used to create a set by passing in dummy values. + * Exceptions include BidiMap implementations, as they require unique values. + * + * @since 3.1 + * @version $Id: MapBackedSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class MapBackedSet implements Set, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 6723912213766056587L; + + /** The map being used as the backing store */ + private final Map map; + + /** The dummyValue to use */ + private final V dummyValue; + + /** + * Factory method to create a set from a map. + * + * @param the element type + * @param the dummy value type in the map + * @param map the map to decorate, must not be null + * @return a new map backed set + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static MapBackedSet mapBackedSet(final Map map) { + return mapBackedSet(map, null); + } + + /** + * Factory method to create a set from a map. + * + * @param the element type + * @param the dummy value type in the map + * @param map the map to decorate, must not be null + * @param dummyValue the dummy value to use + * @return a new map backed set + * @throws NullPointerException if map is null + * @since 4.0 + */ + public static MapBackedSet mapBackedSet(final Map map, final V dummyValue) { + return new MapBackedSet(map, dummyValue); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param map the map to decorate, must not be null + * @param dummyValue the dummy value to use + * @throws NullPointerException if map is null + */ + private MapBackedSet(final Map map, final V dummyValue) { + super(); + if (map == null) { + throw new NullPointerException("The map must not be null"); + } + this.map = map; + this.dummyValue = dummyValue; + } + + //----------------------------------------------------------------------- + public int size() { + return map.size(); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public Iterator iterator() { + return map.keySet().iterator(); + } + + public boolean contains(final Object obj) { + return map.containsKey(obj); + } + + public boolean containsAll(final Collection coll) { + return map.keySet().containsAll(coll); + } + + public boolean add(final E obj) { + final int size = map.size(); + map.put(obj, dummyValue); + return map.size() != size; + } + + public boolean addAll(final Collection coll) { + final int size = map.size(); + for (final E e : coll) { + map.put(e, dummyValue); + } + return map.size() != size; + } + + public boolean remove(final Object obj) { + final int size = map.size(); + map.remove(obj); + return map.size() != size; + } + + public boolean removeAll(final Collection coll) { + return map.keySet().removeAll(coll); + } + + public boolean retainAll(final Collection coll) { + return map.keySet().retainAll(coll); + } + + public void clear() { + map.clear(); + } + + public Object[] toArray() { + return map.keySet().toArray(); + } + + public T[] toArray(final T[] array) { + return map.keySet().toArray(array); + } + + @Override + public boolean equals(final Object obj) { + return map.keySet().equals(obj); + } + + @Override + public int hashCode() { + return map.keySet().hashCode(); + } + +} diff --git a/src/org/apache/commons/collections4/set/PredicatedNavigableSet.java b/src/org/apache/commons/collections4/set/PredicatedNavigableSet.java new file mode 100644 index 0000000..3425f4c --- /dev/null +++ b/src/org/apache/commons/collections4/set/PredicatedNavigableSet.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Iterator; +import java.util.NavigableSet; + +import org.apache.commons.collections4.Predicate; + +/** + * Decorates another NavigableSet to validate that all additions + * match a specified predicate. + *

              + * This set exists to provide validation for the decorated set. + * It is normally created to decorate an empty set. + * If an object cannot be added to the set, an IllegalArgumentException is thrown. + *

              + * One usage would be to ensure that no null entries are added to the set. + *

              + * NavigableSet set =
              + *   PredicatedSortedSet.predicatedNavigableSet(new TreeSet(),
              + *                                              NotNullPredicate.notNullPredicate());
              + * 
              + * + * @since 4.1 + * @version $Id: PredicatedNavigableSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedNavigableSet extends PredicatedSortedSet implements NavigableSet { + + /** Serialization version */ + private static final long serialVersionUID = 20150528L; + + /** + * Factory method to create a predicated (validating) navigable set. + *

              + * If there are any elements already in the set being decorated, they + * are validated. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated navigable set. + * @throws NullPointerException if set or predicate is null + * @throws IllegalArgumentException if the set contains invalid elements + * @since 4.0 + */ + public static PredicatedNavigableSet predicatedNavigableSet(final NavigableSet set, + final Predicate predicate) { + return new PredicatedNavigableSet(set, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the set being decorated, they + * are validated. + * + * @param set the set to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if set or predicate is null + * @throws IllegalArgumentException if the set contains invalid elements + */ + protected PredicatedNavigableSet(final NavigableSet set, final Predicate predicate) { + super(set, predicate); + } + + /** + * Gets the navigable set being decorated. + * + * @return the decorated navigable set + */ + @Override + protected NavigableSet decorated() { + return (NavigableSet) super.decorated(); + } + + //----------------------------------------------------------------------- + + @Override + public E lower(E e) { + return decorated().lower(e); + } + + @Override + public E floor(E e) { + return decorated().floor(e); + } + + @Override + public E ceiling(E e) { + return decorated().ceiling(e); + } + + @Override + public E higher(E e) { + return decorated().higher(e); + } + + @Override + public E pollFirst() { + return decorated().pollFirst(); + } + + @Override + public E pollLast() { + return decorated().pollLast(); + } + + @Override + public NavigableSet descendingSet() { + return predicatedNavigableSet(decorated().descendingSet(), predicate); + } + + @Override + public Iterator descendingIterator() { + return decorated().descendingIterator(); + } + + @Override + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + final NavigableSet sub = decorated().subSet(fromElement, fromInclusive, toElement, toInclusive); + return predicatedNavigableSet(sub, predicate); + } + + @Override + public NavigableSet headSet(E toElement, boolean inclusive) { + final NavigableSet head = decorated().headSet(toElement, inclusive); + return predicatedNavigableSet(head, predicate); + } + + @Override + public NavigableSet tailSet(E fromElement, boolean inclusive) { + final NavigableSet tail = decorated().tailSet(fromElement, inclusive); + return predicatedNavigableSet(tail, predicate); + } + +} diff --git a/src/org/apache/commons/collections4/set/PredicatedSet.java b/src/org/apache/commons/collections4/set/PredicatedSet.java new file mode 100644 index 0000000..2b62ac8 --- /dev/null +++ b/src/org/apache/commons/collections4/set/PredicatedSet.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Set; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.collection.PredicatedCollection; + +/** + * Decorates another Set to validate that all additions + * match a specified predicate. + *

              + * This set exists to provide validation for the decorated set. + * It is normally created to decorate an empty set. + * If an object cannot be added to the set, an IllegalArgumentException is thrown. + *

              + * One usage would be to ensure that no null entries are added to the set. + *

              Set set = PredicatedSet.decorate(new HashSet(), NotNullPredicate.INSTANCE);
              + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: PredicatedSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedSet extends PredicatedCollection implements Set { + + /** Serialization version */ + private static final long serialVersionUID = -684521469108685117L; + + /** + * Factory method to create a predicated (validating) set. + *

              + * If there are any elements already in the set being decorated, they + * are validated. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a decorated set + * @throws NullPointerException if set or predicate is null + * @throws IllegalArgumentException if the set contains invalid elements + * @since 4.0 + */ + public static PredicatedSet predicatedSet(final Set set, final Predicate predicate) { + return new PredicatedSet(set, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the set being decorated, they + * are validated. + * + * @param set the set to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if set or predicate is null + * @throws IllegalArgumentException if the set contains invalid elements + */ + protected PredicatedSet(final Set set, final Predicate predicate) { + super(set, predicate); + } + + /** + * Gets the set being decorated. + * + * @return the decorated set + */ + @Override + protected Set decorated() { + return (Set) super.decorated(); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + +} diff --git a/src/org/apache/commons/collections4/set/PredicatedSortedSet.java b/src/org/apache/commons/collections4/set/PredicatedSortedSet.java new file mode 100644 index 0000000..5023920 --- /dev/null +++ b/src/org/apache/commons/collections4/set/PredicatedSortedSet.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Comparator; +import java.util.SortedSet; + +import org.apache.commons.collections4.Predicate; + +/** + * Decorates another SortedSet to validate that all additions + * match a specified predicate. + *

              + * This set exists to provide validation for the decorated set. + * It is normally created to decorate an empty set. + * If an object cannot be added to the set, an IllegalArgumentException is thrown. + *

              + * One usage would be to ensure that no null entries are added to the set. + *

              + * SortedSet set =
              + *   PredicatedSortedSet.predicatedSortedSet(new TreeSet(),
              + *                                           NotNullPredicate.notNullPredicate());
              + * 
              + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: PredicatedSortedSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class PredicatedSortedSet extends PredicatedSet implements SortedSet { + + /** Serialization version */ + private static final long serialVersionUID = -9110948148132275052L; + + /** + * Factory method to create a predicated (validating) sorted set. + *

              + * If there are any elements already in the set being decorated, they + * are validated. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @return a new predicated sorted set. + * @throws NullPointerException if set or predicate is null + * @throws IllegalArgumentException if the set contains invalid elements + * @since 4.0 + */ + public static PredicatedSortedSet predicatedSortedSet(final SortedSet set, + final Predicate predicate) { + return new PredicatedSortedSet(set, predicate); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the set being decorated, they + * are validated. + * + * @param set the set to decorate, must not be null + * @param predicate the predicate to use for validation, must not be null + * @throws NullPointerException if set or predicate is null + * @throws IllegalArgumentException if the set contains invalid elements + */ + protected PredicatedSortedSet(final SortedSet set, final Predicate predicate) { + super(set, predicate); + } + + /** + * Gets the sorted set being decorated. + * + * @return the decorated sorted set + */ + @Override + protected SortedSet decorated() { + return (SortedSet) super.decorated(); + } + + //----------------------------------------------------------------------- + public Comparator comparator() { + return decorated().comparator(); + } + + public E first() { + return decorated().first(); + } + + public E last() { + return decorated().last(); + } + + public SortedSet subSet(final E fromElement, final E toElement) { + final SortedSet sub = decorated().subSet(fromElement, toElement); + return new PredicatedSortedSet(sub, predicate); + } + + public SortedSet headSet(final E toElement) { + final SortedSet head = decorated().headSet(toElement); + return new PredicatedSortedSet(head, predicate); + } + + public SortedSet tailSet(final E fromElement) { + final SortedSet tail = decorated().tailSet(fromElement); + return new PredicatedSortedSet(tail, predicate); + } + +} diff --git a/src/org/apache/commons/collections4/set/TransformedNavigableSet.java b/src/org/apache/commons/collections4/set/TransformedNavigableSet.java new file mode 100644 index 0000000..ddfe96e --- /dev/null +++ b/src/org/apache/commons/collections4/set/TransformedNavigableSet.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Iterator; +import java.util.NavigableSet; + +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another NavigableSet to transform objects that are added. + *

              + * The add methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + * + * @since 4.1 + * @version $Id: TransformedNavigableSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedNavigableSet extends TransformedSortedSet implements NavigableSet { + + /** Serialization version */ + private static final long serialVersionUID = 20150528L; + + /** + * Factory method to create a transforming navigable set. + *

              + * If there are any elements already in the set being decorated, they + * are NOT transformed. + * Contrast this with {@link #transformedNavigableSet(NavigableSet, Transformer)}. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed {@link NavigableSet} + * @throws NullPointerException if set or transformer is null + */ + public static TransformedNavigableSet transformingNavigableSet(final NavigableSet set, + final Transformer transformer) { + return new TransformedNavigableSet(set, transformer); + } + + /** + * Factory method to create a transforming navigable set that will transform + * existing contents of the specified navigable set. + *

              + * If there are any elements already in the set being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingNavigableSet(NavigableSet, Transformer)}. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed {@link NavigableSet} + * @throws NullPointerException if set or transformer is null + */ + public static TransformedNavigableSet transformedNavigableSet(final NavigableSet set, + final Transformer transformer) { + + final TransformedNavigableSet decorated = new TransformedNavigableSet(set, transformer); + if (set.size() > 0) { + @SuppressWarnings("unchecked") // set is type E + final E[] values = (E[]) set.toArray(); // NOPMD - false positive for generics + set.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the set being decorated, they + * are NOT transformed. + * + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if set or transformer is null + */ + protected TransformedNavigableSet(final NavigableSet set, + final Transformer transformer) { + super(set, transformer); + } + + /** + * Gets the decorated navigable set. + * + * @return the decorated navigable set + */ + @Override + protected NavigableSet decorated() { + return (NavigableSet) super.decorated(); + } + + //----------------------------------------------------------------------- + + @Override + public E lower(E e) { + return decorated().lower(e); + } + + @Override + public E floor(E e) { + return decorated().floor(e); + } + + @Override + public E ceiling(E e) { + return decorated().ceiling(e); + } + + @Override + public E higher(E e) { + return decorated().higher(e); + } + + @Override + public E pollFirst() { + return decorated().pollFirst(); + } + + @Override + public E pollLast() { + return decorated().pollLast(); + } + + @Override + public NavigableSet descendingSet() { + return transformingNavigableSet(decorated().descendingSet(), transformer); + } + + @Override + public Iterator descendingIterator() { + return decorated().descendingIterator(); + } + + @Override + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + final NavigableSet sub = decorated().subSet(fromElement, fromInclusive, toElement, toInclusive); + return transformingNavigableSet(sub, transformer); + } + + @Override + public NavigableSet headSet(E toElement, boolean inclusive) { + final NavigableSet head = decorated().headSet(toElement, inclusive); + return transformingNavigableSet(head, transformer); + } + + @Override + public NavigableSet tailSet(E fromElement, boolean inclusive) { + final NavigableSet tail = decorated().tailSet(fromElement, inclusive); + return transformingNavigableSet(tail, transformer); + } + +} diff --git a/src/org/apache/commons/collections4/set/TransformedSet.java b/src/org/apache/commons/collections4/set/TransformedSet.java new file mode 100644 index 0000000..7bf774f --- /dev/null +++ b/src/org/apache/commons/collections4/set/TransformedSet.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Set; + +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.collection.TransformedCollection; + +/** + * Decorates another Set to transform objects that are added. + *

              + * The add methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: TransformedSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedSet extends TransformedCollection implements Set { + + /** Serialization version */ + private static final long serialVersionUID = 306127383500410386L; + + /** + * Factory method to create a transforming set. + *

              + * If there are any elements already in the set being decorated, they + * are NOT transformed. + * Contrast this with {@link #transformedSet(Set, Transformer)}. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed set + * @throws NullPointerException if set or transformer is null + * @since 4.0 + */ + public static TransformedSet transformingSet(final Set set, + final Transformer transformer) { + return new TransformedSet(set, transformer); + } + + /** + * Factory method to create a transforming set that will transform + * existing contents of the specified set. + *

              + * If there are any elements already in the set being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingSet(Set, Transformer)}. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed set + * @throws NullPointerException if set or transformer is null + * @since 4.0 + */ + public static Set transformedSet(final Set set, final Transformer transformer) { + final TransformedSet decorated = new TransformedSet(set, transformer); + if (set.size() > 0) { + @SuppressWarnings("unchecked") // set is type E + final E[] values = (E[]) set.toArray(); // NOPMD - false positive for generics + set.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the set being decorated, they + * are NOT transformed. + * + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if set or transformer is null + */ + protected TransformedSet(final Set set, final Transformer transformer) { + super(set, transformer); + } + + @Override + public boolean equals(final Object object) { + return object == this || decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + +} diff --git a/src/org/apache/commons/collections4/set/TransformedSortedSet.java b/src/org/apache/commons/collections4/set/TransformedSortedSet.java new file mode 100644 index 0000000..ac3834c --- /dev/null +++ b/src/org/apache/commons/collections4/set/TransformedSortedSet.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Comparator; +import java.util.SortedSet; + +import org.apache.commons.collections4.Transformer; + +/** + * Decorates another SortedSet to transform objects that are added. + *

              + * The add methods are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must + * use the Integer form to remove objects. + *

              + * This class is Serializable from Commons Collections 3.1. + * + * @since 3.0 + * @version $Id: TransformedSortedSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class TransformedSortedSet extends TransformedSet implements SortedSet { + + /** Serialization version */ + private static final long serialVersionUID = -1675486811351124386L; + + /** + * Factory method to create a transforming sorted set. + *

              + * If there are any elements already in the set being decorated, they + * are NOT transformed. + * Contrast this with {@link #transformedSortedSet(SortedSet, Transformer)}. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed {@link SortedSet} + * @throws NullPointerException if set or transformer is null + * @since 4.0 + */ + public static TransformedSortedSet transformingSortedSet(final SortedSet set, + final Transformer transformer) { + return new TransformedSortedSet(set, transformer); + } + + /** + * Factory method to create a transforming sorted set that will transform + * existing contents of the specified sorted set. + *

              + * If there are any elements already in the set being decorated, they + * will be transformed by this method. + * Contrast this with {@link #transformingSortedSet(SortedSet, Transformer)}. + * + * @param the element type + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @return a new transformed {@link SortedSet} + * @throws NullPointerException if set or transformer is null + * @since 4.0 + */ + public static TransformedSortedSet transformedSortedSet(final SortedSet set, + final Transformer transformer) { + + final TransformedSortedSet decorated = new TransformedSortedSet(set, transformer); + if (set.size() > 0) { + @SuppressWarnings("unchecked") // set is type E + final E[] values = (E[]) set.toArray(); // NOPMD - false positive for generics + set.clear(); + for (final E value : values) { + decorated.decorated().add(transformer.transform(value)); + } + } + return decorated; + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the set being decorated, they + * are NOT transformed. + * + * @param set the set to decorate, must not be null + * @param transformer the transformer to use for conversion, must not be null + * @throws NullPointerException if set or transformer is null + */ + protected TransformedSortedSet(final SortedSet set, final Transformer transformer) { + super(set, transformer); + } + + /** + * Gets the decorated set. + * + * @return the decorated set + */ + protected SortedSet getSortedSet() { + return (SortedSet) decorated(); + } + + //----------------------------------------------------------------------- + public E first() { + return getSortedSet().first(); + } + + public E last() { + return getSortedSet().last(); + } + + public Comparator comparator() { + return getSortedSet().comparator(); + } + + //----------------------------------------------------------------------- + public SortedSet subSet(final E fromElement, final E toElement) { + final SortedSet set = getSortedSet().subSet(fromElement, toElement); + return new TransformedSortedSet(set, transformer); + } + + public SortedSet headSet(final E toElement) { + final SortedSet set = getSortedSet().headSet(toElement); + return new TransformedSortedSet(set, transformer); + } + + public SortedSet tailSet(final E fromElement) { + final SortedSet set = getSortedSet().tailSet(fromElement); + return new TransformedSortedSet(set, transformer); + } + +} diff --git a/src/org/apache/commons/collections4/set/UnmodifiableNavigableSet.java b/src/org/apache/commons/collections4/set/UnmodifiableNavigableSet.java new file mode 100644 index 0000000..3be017a --- /dev/null +++ b/src/org/apache/commons/collections4/set/UnmodifiableNavigableSet.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.SortedSet; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; + +/** + * Decorates another NavigableSet to ensure it can't be altered. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 4.1 + * @version $Id: UnmodifiableNavigableSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableNavigableSet + extends AbstractNavigableSetDecorator + implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = 20150528L; + + /** + * Factory method to create an unmodifiable set. + * + * @param the element type + * @param set the set to decorate, must not be null + * @return a new unmodifiable {@link NavigableSet} + * @throws NullPointerException if set is null + */ + public static NavigableSet unmodifiableNavigableSet(final NavigableSet set) { + if (set instanceof Unmodifiable) { + return set; + } + return new UnmodifiableNavigableSet(set); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws NullPointerException if set is null + */ + private UnmodifiableNavigableSet(final NavigableSet set) { + super(set); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + // SortedSet + //----------------------------------------------------------------------- + @Override + public SortedSet subSet(final E fromElement, final E toElement) { + final SortedSet sub = decorated().subSet(fromElement, toElement); + return UnmodifiableSortedSet.unmodifiableSortedSet(sub); + } + + @Override + public SortedSet headSet(final E toElement) { + final SortedSet head = decorated().headSet(toElement); + return UnmodifiableSortedSet.unmodifiableSortedSet(head); + } + + @Override + public SortedSet tailSet(final E fromElement) { + final SortedSet tail = decorated().tailSet(fromElement); + return UnmodifiableSortedSet.unmodifiableSortedSet(tail); + } + + // NavigableSet + //----------------------------------------------------------------------- + @Override + public NavigableSet descendingSet() { + return unmodifiableNavigableSet(decorated().descendingSet()); + } + + @Override + public Iterator descendingIterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().descendingIterator()); + } + + @Override + public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { + final NavigableSet sub = decorated().subSet(fromElement, fromInclusive, toElement, toInclusive); + return unmodifiableNavigableSet(sub); + } + + @Override + public NavigableSet headSet(E toElement, boolean inclusive) { + final NavigableSet head = decorated().headSet(toElement, inclusive); + return unmodifiableNavigableSet(head); + } + + @Override + public NavigableSet tailSet(E fromElement, boolean inclusive) { + final NavigableSet tail = decorated().tailSet(fromElement, inclusive); + return unmodifiableNavigableSet(tail); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); // (1) + } + +} diff --git a/src/org/apache/commons/collections4/set/UnmodifiableSet.java b/src/org/apache/commons/collections4/set/UnmodifiableSet.java new file mode 100644 index 0000000..a81b3f2 --- /dev/null +++ b/src/org/apache/commons/collections4/set/UnmodifiableSet.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; + +/** + * Decorates another Set to ensure it can't be altered. + *

              + * This class is Serializable from Commons Collections 3.1. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableSet + extends AbstractSerializableSetDecorator + implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = 6499119872185240161L; + + /** + * Factory method to create an unmodifiable set. + * + * @param the element type + * @param set the set to decorate, must not be null + * @return a new unmodifiable set + * @throws NullPointerException if set is null + * @since 4.0 + */ + public static Set unmodifiableSet(final Set set) { + if (set instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final Set tmpSet = (Set) set; + return tmpSet; + } + return new UnmodifiableSet(set); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws NullPointerException if set is null + */ + @SuppressWarnings("unchecked") // safe to upcast + private UnmodifiableSet(final Set set) { + super((Set) set); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/org/apache/commons/collections4/set/UnmodifiableSortedSet.java b/src/org/apache/commons/collections4/set/UnmodifiableSortedSet.java new file mode 100644 index 0000000..6e600c8 --- /dev/null +++ b/src/org/apache/commons/collections4/set/UnmodifiableSortedSet.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.set; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.SortedSet; + +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableIterator; + +/** + * Decorates another SortedSet to ensure it can't be altered. + *

              + * This class is Serializable from Commons Collections 3.1. + *

              + * Attempts to modify it will result in an UnsupportedOperationException. + * + * @since 3.0 + * @version $Id: UnmodifiableSortedSet.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public final class UnmodifiableSortedSet + extends AbstractSortedSetDecorator + implements Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = -725356885467962424L; + + /** + * Factory method to create an unmodifiable set. + * + * @param the element type + * @param set the set to decorate, must not be null + * @return a new unmodifiable {@link SortedSet} + * @throws NullPointerException if set is null + * @since 4.0 + */ + public static SortedSet unmodifiableSortedSet(final SortedSet set) { + if (set instanceof Unmodifiable) { + return set; + } + return new UnmodifiableSortedSet(set); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param set the set to decorate, must not be null + * @throws NullPointerException if set is null + */ + private UnmodifiableSortedSet(final SortedSet set) { + super(set); + } + + //----------------------------------------------------------------------- + @Override + public Iterator iterator() { + return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); + } + + @Override + public boolean add(final E object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection coll) { + throw new UnsupportedOperationException(); + } + + //----------------------------------------------------------------------- + @Override + public SortedSet subSet(final E fromElement, final E toElement) { + final SortedSet sub = decorated().subSet(fromElement, toElement); + return unmodifiableSortedSet(sub); + } + + @Override + public SortedSet headSet(final E toElement) { + final SortedSet head = decorated().headSet(toElement); + return unmodifiableSortedSet(head); + } + + @Override + public SortedSet tailSet(final E fromElement) { + final SortedSet tail = decorated().tailSet(fromElement); + return unmodifiableSortedSet(tail); + } + + //----------------------------------------------------------------------- + /** + * Write the collection out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the collection in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + setCollection((Collection) in.readObject()); // (1) + } + +} diff --git a/src/org/apache/commons/collections4/set/package-info.java b/src/org/apache/commons/collections4/set/package-info.java new file mode 100644 index 0000000..de4d446 --- /dev/null +++ b/src/org/apache/commons/collections4/set/package-info.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the {@link java.util.Set Set}, + * {@link java.util.SortedSet SortedSet} and + * {@link java.util.NavigableSet NavigableSet} interfaces. + *

              + * The implementations are in the form of direct implementations and decorators. + * A decorator wraps another implementation of the interface to add some + * specific additional functionality. + *

              + * The following implementations are provided in the package: + *

                + *
              • CompositeSet - a set that combines multiple sets into one + *
              + * The following decorators are provided in the package: + *
                + *
              • Unmodifiable - ensures the collection cannot be altered + *
              • Predicated - ensures that only elements that are valid according to a predicate can be added + *
              • Transformed - transforms each element added + *
              • ListOrdered - ensures that insertion order is retained + *
              • MapBackedSet - a set formed by decorating a Map + *
              + * + * @version $Id: package-info.java 1682768 2015-05-31 18:35:18Z tn $ + */ +package org.apache.commons.collections4.set; diff --git a/src/org/apache/commons/collections4/splitmap/AbstractIterableGetMapDecorator.java b/src/org/apache/commons/collections4/splitmap/AbstractIterableGetMapDecorator.java new file mode 100644 index 0000000..12d216e --- /dev/null +++ b/src/org/apache/commons/collections4/splitmap/AbstractIterableGetMapDecorator.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.splitmap; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections4.IterableGet; +import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.map.EntrySetToMapIteratorAdapter; + +/** + * {@link IterableGet} that uses a {@link Map} for the + * {@link org.apache.commons.collections4.Get Get} implementation. + * + * @since 4.0 + * @version $Id: AbstractIterableGetMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class AbstractIterableGetMapDecorator implements IterableGet { + + /** The map to decorate */ + transient Map map; + + /** + * Create a new AbstractSplitMapDecorator. + * @param map the map to decorate, must not be null + * @throws NullPointerException if map is null + */ + public AbstractIterableGetMapDecorator(final Map map) { + if (map == null) { + throw new NullPointerException("Map must not be null."); + } + this.map = map; + } + + /** + * Constructor only used in deserialization, do not use otherwise. + */ + protected AbstractIterableGetMapDecorator() { + super(); + } + + /** + * Gets the map being decorated. + * + * @return the decorated map + */ + protected Map decorated() { + return map; + } + + public boolean containsKey(final Object key) { + return decorated().containsKey(key); + } + + public boolean containsValue(final Object value) { + return decorated().containsValue(value); + } + + public Set> entrySet() { + return decorated().entrySet(); + } + + public V get(final Object key) { + return decorated().get(key); + } + + public V remove(final Object key) { + return decorated().remove(key); + } + + public boolean isEmpty() { + return decorated().isEmpty(); + } + + public Set keySet() { + return decorated().keySet(); + } + + public int size() { + return decorated().size(); + } + + public Collection values() { + return decorated().values(); + } + + /** + * Get a MapIterator over this Get. + * @return MapIterator + */ + public MapIterator mapIterator() { + return new EntrySetToMapIteratorAdapter(entrySet()); + } + + @Override + public boolean equals(final Object object) { + if (object == this) { + return true; + } + return decorated().equals(object); + } + + @Override + public int hashCode() { + return decorated().hashCode(); + } + + @Override + public String toString() { + return decorated().toString(); + } + +} diff --git a/src/org/apache/commons/collections4/splitmap/TransformedSplitMap.java b/src/org/apache/commons/collections4/splitmap/TransformedSplitMap.java new file mode 100644 index 0000000..a5a4368 --- /dev/null +++ b/src/org/apache/commons/collections4/splitmap/TransformedSplitMap.java @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.splitmap; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +import org.apache.commons.collections4.Put; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.map.LinkedMap; + +/** + * Decorates another {@link Map} to transform objects that are added. + *

              + * The Map put methods and Map.Entry setValue method are affected by this class. + * Thus objects must be removed or searched for using their transformed form. + * For example, if the transformation converts Strings to Integers, you must use + * the Integer form to remove objects. + *

              + * Note that TransformedMap is not synchronized and is not + * thread-safe. If you wish to use this map from multiple threads + * concurrently, you must use appropriate synchronization. The simplest approach + * is to wrap this map using {@link java.util.Collections#synchronizedMap(Map)}. + * This class may throw exceptions when accessed by concurrent threads without + * synchronization. + *

              + * The "put" and "get" type constraints of this class are mutually independent; + * contrast with {@link org.apache.commons.collections4.map.TransformedMap} which, + * by virtue of its implementing {@link Map}<K, V>, must be constructed in such + * a way that its read and write parameters are generalized to a common (super-)type. + * In practice this would often mean >Object, Object>, defeating + * much of the usefulness of having parameterized types. + *

              + * On the downside, this class is not drop-in compatible with {@link java.util.Map} + * but is intended to be worked with either directly or by {@link Put} and + * {@link org.apache.commons.collections4.Get Get} generalizations. + * + * @since 4.0 + * @version $Id: TransformedSplitMap.java 1686855 2015-06-22 13:00:27Z tn $ + * + * @see org.apache.commons.collections4.SplitMapUtils#readableMap(org.apache.commons.collections4.Get) + * @see org.apache.commons.collections4.SplitMapUtils#writableMap(Put) + */ +public class TransformedSplitMap extends AbstractIterableGetMapDecorator + implements Put, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 5966875321133456994L; + + /** The transformer to use for the key */ + private final Transformer keyTransformer; + /** The transformer to use for the value */ + private final Transformer valueTransformer; + + /** + * Factory method to create a transforming map. + *

              + * If there are any elements already in the map being decorated, they are + * NOT transformed. + * + * @param the input key type + * @param the output key type + * @param the input value type + * @param the output value type + * @param map the map to decorate, must not be null + * @param keyTransformer the transformer to use for key conversion, must not be null + * @param valueTransformer the transformer to use for value conversion, must not be null + * @return a new transformed map + * @throws NullPointerException if map or either of the transformers is null + */ + public static TransformedSplitMap transformingMap(final Map map, + final Transformer keyTransformer, + final Transformer valueTransformer) { + return new TransformedSplitMap(map, keyTransformer, valueTransformer); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + *

              + * If there are any elements already in the collection being decorated, they + * are NOT transformed. + * + * @param map the map to decorate, must not be null + * @param keyTransformer the transformer to use for key conversion, must not be null + * @param valueTransformer the transformer to use for value conversion, must not be null + * @throws NullPointerException if map or either of the transformers is null + */ + protected TransformedSplitMap(final Map map, final Transformer keyTransformer, + final Transformer valueTransformer) { + super(map); + if (keyTransformer == null) { + throw new NullPointerException("KeyTransformer must not be null."); + } + this.keyTransformer = keyTransformer; + if (valueTransformer == null) { + throw new NullPointerException("ValueTransformer must not be null."); + } + this.valueTransformer = valueTransformer; + } + + //----------------------------------------------------------------------- + /** + * Write the map out using a custom routine. + * + * @param out the output stream + * @throws IOException + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeObject(decorated()); + } + + /** + * Read the map in using a custom routine. + * + * @param in the input stream + * @throws IOException + * @throws ClassNotFoundException + * @since 3.1 + */ + @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + map = (Map) in.readObject(); // (1) + } + + //----------------------------------------------------------------------- + /** + * Transforms a key. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param object the object to transform + * @return the transformed object + */ + protected K transformKey(final J object) { + return keyTransformer.transform(object); + } + + /** + * Transforms a value. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param object the object to transform + * @return the transformed object + */ + protected V transformValue(final U object) { + return valueTransformer.transform(object); + } + + /** + * Transforms a map. + *

              + * The transformer itself may throw an exception if necessary. + * + * @param map the map to transform + * @return the transformed object + */ + @SuppressWarnings("unchecked") + protected Map transformMap(final Map map) { + if (map.isEmpty()) { + return (Map) map; + } + final Map result = new LinkedMap(map.size()); + + for (final Map.Entry entry : map.entrySet()) { + result.put(transformKey(entry.getKey()), transformValue(entry.getValue())); + } + return result; + } + + /** + * Override to transform the value when using setValue. + * + * @param value the value to transform + * @return the transformed value + */ + protected V checkSetValue(final U value) { + return valueTransformer.transform(value); + } + + //----------------------------------------------------------------------- + public V put(final J key, final U value) { + return decorated().put(transformKey(key), transformValue(value)); + } + + public void putAll(final Map mapToCopy) { + decorated().putAll(transformMap(mapToCopy)); + } + + public void clear() { + decorated().clear(); + } +} diff --git a/src/org/apache/commons/collections4/splitmap/package-info.java b/src/org/apache/commons/collections4/splitmap/package-info.java new file mode 100644 index 0000000..405be61 --- /dev/null +++ b/src/org/apache/commons/collections4/splitmap/package-info.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * The "split map" concept is that of an object that implements + * the {@link org.apache.commons.collections4.Put Put} and + * {@link org.apache.commons.collections4.Get Get} interfaces, + * with differing generic types. This is like a pre-generics + * {@link java.util.Map Map} whose input key/value constraints are + * different than its output key/value constraints. While it would + * be possible to declare a "split map" with matching input/output + * key/value constraints, this would be a {@link java.util.Map Map} + * and would therefore make little sense (any Commons Collections + * {@link java.util.Map Map} implementation will also implement + * {@link org.apache.commons.collections4.Put Put} and + * {@link org.apache.commons.collections4.Get Get} with matching + * generic parameters). + *

              + * The following decorators are provided: + *

                + *
              • Transformed - transforms each element added + *
              + * + * @version $Id: package-info.java 1469004 2013-04-17 17:37:03Z tn $ + */ +package org.apache.commons.collections4.splitmap; diff --git a/src/org/apache/commons/collections4/trie/AbstractBitwiseTrie.java b/src/org/apache/commons/collections4/trie/AbstractBitwiseTrie.java new file mode 100644 index 0000000..557590c --- /dev/null +++ b/src/org/apache/commons/collections4/trie/AbstractBitwiseTrie.java @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.trie; + +import java.io.Serializable; +import java.util.AbstractMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.collections4.Trie; + +/** + * This class provides some basic {@link Trie} functionality and + * utility methods for actual bitwise {@link Trie} implementations. + * + * @since 4.0 + * @version $Id: AbstractBitwiseTrie.java 1492866 2013-06-13 21:01:00Z tn $ + */ +public abstract class AbstractBitwiseTrie extends AbstractMap + implements Trie, Serializable { + + private static final long serialVersionUID = 5826987063535505652L; + + /** + * The {@link KeyAnalyzer} that's being used to build the PATRICIA {@link Trie}. + */ + private final KeyAnalyzer keyAnalyzer; + + /** + * Constructs a new {@link Trie} using the given {@link KeyAnalyzer}. + * + * @param keyAnalyzer the {@link KeyAnalyzer} to use + */ + protected AbstractBitwiseTrie(final KeyAnalyzer keyAnalyzer) { + if (keyAnalyzer == null) { + throw new NullPointerException("keyAnalyzer"); + } + + this.keyAnalyzer = keyAnalyzer; + } + + /** + * Returns the {@link KeyAnalyzer} that constructed the {@link Trie}. + * @return the {@link KeyAnalyzer} used by this {@link Trie} + */ + protected KeyAnalyzer getKeyAnalyzer() { + return keyAnalyzer; + } + + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + buffer.append("Trie[").append(size()).append("]={\n"); + for (final Map.Entry entry : entrySet()) { + buffer.append(" ").append(entry).append("\n"); + } + buffer.append("}\n"); + return buffer.toString(); + } + + /** + * A utility method to cast keys. It actually doesn't cast anything. It's just fooling the compiler! + */ + @SuppressWarnings("unchecked") + final K castKey(final Object key) { + return (K) key; + } + + /** + * Returns the length of the given key in bits + * + * @see KeyAnalyzer#lengthInBits(Object) + */ + final int lengthInBits(final K key) { + if (key == null) { + return 0; + } + + return keyAnalyzer.lengthInBits(key); + } + + /** + * Returns the number of bits per element in the key + * + * @see KeyAnalyzer#bitsPerElement() + */ + final int bitsPerElement() { + return keyAnalyzer.bitsPerElement(); + } + + /** + * Returns whether or not the given bit on the key is set or false if the key is null. + * + * @see KeyAnalyzer#isBitSet(Object, int, int) + */ + final boolean isBitSet(final K key, final int bitIndex, final int lengthInBits) { + if (key == null) { // root's might be null! + return false; + } + return keyAnalyzer.isBitSet(key, bitIndex, lengthInBits); + } + + /** + * Utility method for calling {@link KeyAnalyzer#bitIndex(Object, int, int, Object, int, int)}. + */ + final int bitIndex(final K key, final K foundKey) { + return keyAnalyzer.bitIndex(key, 0, lengthInBits(key), foundKey, 0, lengthInBits(foundKey)); + } + + /** + * An utility method for calling {@link KeyAnalyzer#compare(Object, Object)} + */ + final boolean compareKeys(final K key, final K other) { + if (key == null) { + return other == null; + } else if (other == null) { + return false; + } + + return keyAnalyzer.compare(key, other) == 0; + } + + /** + * Returns true if both values are either null or equal. + */ + static boolean compare(final Object a, final Object b) { + return a == null ? b == null : a.equals(b); + } + + /** + * A basic implementation of {@link Entry}. + */ + abstract static class BasicEntry implements Map.Entry, Serializable { + + private static final long serialVersionUID = -944364551314110330L; + + protected K key; + + protected V value; + + public BasicEntry(final K key) { + this.key = key; + } + + public BasicEntry(final K key, final V value) { + this.key = key; + this.value = value; + } + + /** + * Replaces the current key and value with the provided key & value. + */ + public V setKeyValue(final K key, final V value) { + this.key = key; + return setValue(value); + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public V setValue(final V value) { + final V previous = this.value; + this.value = value; + return previous; + } + + @Override + public int hashCode() { + return (getKey() == null ? 0 : getKey().hashCode()) ^ + (getValue() == null ? 0 : getValue().hashCode()); + } + + @Override + public boolean equals(final Object o) { + if (o == this) { + return true; + } else if (!(o instanceof Map.Entry)) { + return false; + } + + final Map.Entry other = (Map.Entry)o; + if (compare(key, other.getKey()) + && compare(value, other.getValue())) { + return true; + } + return false; + } + + @Override + public String toString() { + return key + "=" + value; + } + } +} diff --git a/src/org/apache/commons/collections4/trie/AbstractPatriciaTrie.java b/src/org/apache/commons/collections4/trie/AbstractPatriciaTrie.java new file mode 100644 index 0000000..56691fa --- /dev/null +++ b/src/org/apache/commons/collections4/trie/AbstractPatriciaTrie.java @@ -0,0 +1,2406 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.trie; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.AbstractCollection; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.SortedMap; + +import org.apache.commons.collections4.OrderedMapIterator; + +/** + * This class implements the base PATRICIA algorithm and everything that + * is related to the {@link Map} interface. + * + * @since 4.0 + * @version $Id: AbstractPatriciaTrie.java 1648941 2015-01-01 21:10:46Z tn $ + */ +abstract class AbstractPatriciaTrie extends AbstractBitwiseTrie { + + private static final long serialVersionUID = 5155253417231339498L; + + /** The root node of the {@link Trie}. */ + private transient TrieEntry root = new TrieEntry(null, null, -1); + + /** + * 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. + */ + private transient volatile Set keySet; + private transient volatile Collection values; + private transient volatile Set> entrySet; + + /** The current size of the {@link Trie}. */ + private transient int size = 0; + + /** + * The number of times this {@link Trie} has been modified. + * It's used to detect concurrent modifications and fail-fast the {@link Iterator}s. + */ + protected transient int modCount = 0; + + protected AbstractPatriciaTrie(final KeyAnalyzer keyAnalyzer) { + super(keyAnalyzer); + } + + /** + * Constructs a new {@link org.apache.commons.collections4.Trie Trie} using the given + * {@link KeyAnalyzer} and initializes the {@link org.apache.commons.collections4.Trie Trie} + * with the values from the provided {@link Map}. + */ + protected AbstractPatriciaTrie(final KeyAnalyzer keyAnalyzer, + final Map map) { + super(keyAnalyzer); + putAll(map); + } + + //----------------------------------------------------------------------- + @Override + public void clear() { + root.key = null; + root.bitIndex = -1; + root.value = null; + + root.parent = null; + root.left = root; + root.right = null; + root.predecessor = root; + + size = 0; + incrementModCount(); + } + + @Override + public int size() { + return size; + } + + /** + * A helper method to increment the {@link Trie} size and the modification counter. + */ + void incrementSize() { + size++; + incrementModCount(); + } + + /** + * A helper method to decrement the {@link Trie} size and increment the modification counter. + */ + void decrementSize() { + size--; + incrementModCount(); + } + + /** + * A helper method to increment the modification counter. + */ + private void incrementModCount() { + ++modCount; + } + + @Override + public V put(final K key, final V value) { + if (key == null) { + throw new NullPointerException("Key cannot be null"); + } + + final int lengthInBits = lengthInBits(key); + + // The only place to store a key with a length + // of zero bits is the root node + if (lengthInBits == 0) { + if (root.isEmpty()) { + incrementSize(); + } else { + incrementModCount(); + } + return root.setKeyValue(key, value); + } + + final TrieEntry found = getNearestEntryForKey(key, lengthInBits); + if (compareKeys(key, found.key)) { + if (found.isEmpty()) { // <- must be the root + incrementSize(); + } else { + incrementModCount(); + } + return found.setKeyValue(key, value); + } + + final int bitIndex = bitIndex(key, found.key); + if (!KeyAnalyzer.isOutOfBoundsIndex(bitIndex)) { + if (KeyAnalyzer.isValidBitIndex(bitIndex)) { // in 99.999...9% the case + /* NEW KEY+VALUE TUPLE */ + final TrieEntry t = new TrieEntry(key, value, bitIndex); + addEntry(t, lengthInBits); + incrementSize(); + return null; + } else if (KeyAnalyzer.isNullBitKey(bitIndex)) { + // A bits of the Key are zero. The only place to + // store such a Key is the root Node! + + /* NULL BIT KEY */ + if (root.isEmpty()) { + incrementSize(); + } else { + incrementModCount(); + } + return root.setKeyValue(key, value); + + } else if (KeyAnalyzer.isEqualBitKey(bitIndex)) { + // This is a very special and rare case. + + /* REPLACE OLD KEY+VALUE */ + if (found != root) { + incrementModCount(); + return found.setKeyValue(key, value); + } + } + } + + throw new IllegalArgumentException("Failed to put: " + key + " -> " + value + ", " + bitIndex); + } + + /** + * Adds the given {@link TrieEntry} to the {@link Trie}. + */ + TrieEntry addEntry(final TrieEntry entry, final int lengthInBits) { + TrieEntry current = root.left; + TrieEntry path = root; + while(true) { + if (current.bitIndex >= entry.bitIndex + || current.bitIndex <= path.bitIndex) { + entry.predecessor = entry; + + if (!isBitSet(entry.key, entry.bitIndex, lengthInBits)) { + entry.left = entry; + entry.right = current; + } else { + entry.left = current; + entry.right = entry; + } + + entry.parent = path; + if (current.bitIndex >= entry.bitIndex) { + current.parent = entry; + } + + // if we inserted an uplink, set the predecessor on it + if (current.bitIndex <= path.bitIndex) { + current.predecessor = entry; + } + + if (path == root || !isBitSet(entry.key, path.bitIndex, lengthInBits)) { + path.left = entry; + } else { + path.right = entry; + } + + return entry; + } + + path = current; + + if (!isBitSet(entry.key, current.bitIndex, lengthInBits)) { + current = current.left; + } else { + current = current.right; + } + } + } + + @Override + public V get(final Object k) { + final TrieEntry entry = getEntry(k); + return entry != null ? entry.getValue() : null; + } + + /** + * Returns the entry associated with the specified key in the + * PatriciaTrieBase. Returns null if the map contains no mapping + * for this key. + *

              + * This may throw ClassCastException if the object is not of type K. + */ + TrieEntry getEntry(final Object k) { + final K key = castKey(k); + if (key == null) { + return null; + } + + final int lengthInBits = lengthInBits(key); + final TrieEntry entry = getNearestEntryForKey(key, lengthInBits); + return !entry.isEmpty() && compareKeys(key, entry.key) ? entry : null; + } + + /** + * Returns the {@link Entry} whose key is closest in a bitwise XOR + * metric to the given key. This is NOT lexicographic closeness. + * For example, given the keys: + * + *

                + *
              1. D = 1000100 + *
              2. H = 1001000 + *
              3. L = 1001100 + *
              + * + * If the {@link Trie} contained 'H' and 'L', a lookup of 'D' would + * return 'L', because the XOR distance between D & L is smaller + * than the XOR distance between D & H. + * + * @param key the key to use in the search + * @return the {@link Entry} whose key is closest in a bitwise XOR metric + * to the provided key + */ + public Map.Entry select(final K key) { + final int lengthInBits = lengthInBits(key); + final Reference> reference = new Reference>(); + if (!selectR(root.left, -1, key, lengthInBits, reference)) { + return reference.get(); + } + return null; + } + + /** + * Returns the key that is closest in a bitwise XOR metric to the + * provided key. This is NOT lexicographic closeness! + * + * For example, given the keys: + * + *
                + *
              1. D = 1000100 + *
              2. H = 1001000 + *
              3. L = 1001100 + *
              + * + * If the {@link Trie} contained 'H' and 'L', a lookup of 'D' would + * return 'L', because the XOR distance between D & L is smaller + * than the XOR distance between D & H. + * + * @param key the key to use in the search + * @return the key that is closest in a bitwise XOR metric to the provided key + */ + public K selectKey(final K key) { + final Map.Entry entry = select(key); + if (entry == null) { + return null; + } + return entry.getKey(); + } + + /** + * Returns the value whose key is closest in a bitwise XOR metric to + * the provided key. This is NOT lexicographic closeness! + * + * For example, given the keys: + * + *
                + *
              1. D = 1000100 + *
              2. H = 1001000 + *
              3. L = 1001100 + *
              + * + * If the {@link Trie} contained 'H' and 'L', a lookup of 'D' would + * return 'L', because the XOR distance between D & L is smaller + * than the XOR distance between D & H. + * + * @param key the key to use in the search + * @return the value whose key is closest in a bitwise XOR metric + * to the provided key + */ + public V selectValue(final K key) { + final Map.Entry entry = select(key); + if (entry == null) { + return null; + } + return entry.getValue(); + } + + /** + * This is equivalent to the other {@link #selectR(TrieEntry, int, Object, int, Cursor, Reference)} + * method but without its overhead because we're selecting only one best matching Entry from the {@link Trie}. + */ + private boolean selectR(final TrieEntry h, final int bitIndex, + final K key, final int lengthInBits, + final Reference> reference) { + + if (h.bitIndex <= bitIndex) { + // If we hit the root Node and it is empty + // we have to look for an alternative best + // matching node. + if (!h.isEmpty()) { + reference.set(h); + return false; + } + return true; + } + + if (!isBitSet(key, h.bitIndex, lengthInBits)) { + if (selectR(h.left, h.bitIndex, key, lengthInBits, reference)) { + return selectR(h.right, h.bitIndex, key, lengthInBits, reference); + } + } else { + if (selectR(h.right, h.bitIndex, key, lengthInBits, reference)) { + return selectR(h.left, h.bitIndex, key, lengthInBits, reference); + } + } + return false; + } + + @Override + public boolean containsKey(final Object k) { + if (k == null) { + return false; + } + + final K key = castKey(k); + final int lengthInBits = lengthInBits(key); + final TrieEntry entry = getNearestEntryForKey(key, lengthInBits); + return !entry.isEmpty() && compareKeys(key, entry.key); + } + + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = new EntrySet(); + } + return entrySet; + } + + @Override + public Set keySet() { + if (keySet == null) { + keySet = new KeySet(); + } + return keySet; + } + + @Override + public Collection values() { + if (values == null) { + values = new Values(); + } + return values; + } + + /** + * {@inheritDoc} + * + * @throws ClassCastException if provided key is of an incompatible type + */ + @Override + public V remove(final Object k) { + if (k == null) { + return null; + } + + final K key = castKey(k); + final int lengthInBits = lengthInBits(key); + TrieEntry current = root.left; + TrieEntry path = root; + while (true) { + if (current.bitIndex <= path.bitIndex) { + if (!current.isEmpty() && compareKeys(key, current.key)) { + return removeEntry(current); + } + return null; + } + + path = current; + + if (!isBitSet(key, current.bitIndex, lengthInBits)) { + current = current.left; + } else { + current = current.right; + } + } + } + + /** + * Returns the nearest entry for a given key. This is useful + * for finding knowing if a given key exists (and finding the value + * for it), or for inserting the key. + * + * The actual get implementation. This is very similar to + * selectR but with the exception that it might return the + * root Entry even if it's empty. + */ + TrieEntry getNearestEntryForKey(final K key, final int lengthInBits) { + TrieEntry current = root.left; + TrieEntry path = root; + while(true) { + if (current.bitIndex <= path.bitIndex) { + return current; + } + + path = current; + if (!isBitSet(key, current.bitIndex, lengthInBits)) { + current = current.left; + } else { + current = current.right; + } + } + } + + /** + * Removes a single entry from the {@link Trie}. + * + * If we found a Key (Entry h) then figure out if it's + * an internal (hard to remove) or external Entry (easy + * to remove) + */ + V removeEntry(final TrieEntry h) { + if (h != root) { + if (h.isInternalNode()) { + removeInternalEntry(h); + } else { + removeExternalEntry(h); + } + } + + decrementSize(); + return h.setKeyValue(null, null); + } + + /** + * Removes an external entry from the {@link Trie}. + * + * If it's an external Entry then just remove it. + * This is very easy and straight forward. + */ + private void removeExternalEntry(final TrieEntry h) { + if (h == root) { + throw new IllegalArgumentException("Cannot delete root Entry!"); + } else if (!h.isExternalNode()) { + throw new IllegalArgumentException(h + " is not an external Entry!"); + } + + final TrieEntry parent = h.parent; + final TrieEntry child = h.left == h ? h.right : h.left; + + if (parent.left == h) { + parent.left = child; + } else { + parent.right = child; + } + + // either the parent is changing, or the predecessor is changing. + if (child.bitIndex > parent.bitIndex) { + child.parent = parent; + } else { + child.predecessor = parent; + } + + } + + /** + * Removes an internal entry from the {@link Trie}. + * + * If it's an internal Entry then "good luck" with understanding + * this code. The Idea is essentially that Entry p takes Entry h's + * place in the trie which requires some re-wiring. + */ + private void removeInternalEntry(final TrieEntry h) { + if (h == root) { + throw new IllegalArgumentException("Cannot delete root Entry!"); + } else if (!h.isInternalNode()) { + throw new IllegalArgumentException(h + " is not an internal Entry!"); + } + + final TrieEntry p = h.predecessor; + + // Set P's bitIndex + p.bitIndex = h.bitIndex; + + // Fix P's parent, predecessor and child Nodes + { + final TrieEntry parent = p.parent; + final TrieEntry child = p.left == h ? p.right : p.left; + + // if it was looping to itself previously, + // it will now be pointed from it's parent + // (if we aren't removing it's parent -- + // in that case, it remains looping to itself). + // otherwise, it will continue to have the same + // predecessor. + if (p.predecessor == p && p.parent != h) { + p.predecessor = p.parent; + } + + if (parent.left == p) { + parent.left = child; + } else { + parent.right = child; + } + + if (child.bitIndex > parent.bitIndex) { + child.parent = parent; + } + } + + // Fix H's parent and child Nodes + { + // If H is a parent of its left and right child + // then change them to P + if (h.left.parent == h) { + h.left.parent = p; + } + + if (h.right.parent == h) { + h.right.parent = p; + } + + // Change H's parent + if (h.parent.left == h) { + h.parent.left = p; + } else { + h.parent.right = p; + } + } + + // Copy the remaining fields from H to P + //p.bitIndex = h.bitIndex; + p.parent = h.parent; + p.left = h.left; + p.right = h.right; + + // Make sure that if h was pointing to any uplinks, + // p now points to them. + if (isValidUplink(p.left, p)) { + p.left.predecessor = p; + } + + if (isValidUplink(p.right, p)) { + p.right.predecessor = p; + } + } + + /** + * Returns the entry lexicographically after the given entry. + * If the given entry is null, returns the first node. + */ + TrieEntry nextEntry(final TrieEntry node) { + if (node == null) { + return firstEntry(); + } + return nextEntryImpl(node.predecessor, node, null); + } + + /** + * Scans for the next node, starting at the specified point, and using 'previous' + * as a hint that the last node we returned was 'previous' (so we know not to return + * it again). If 'tree' is non-null, this will limit the search to the given tree. + * + * The basic premise is that each iteration can follow the following steps: + * + * 1) Scan all the way to the left. + * a) If we already started from this node last time, proceed to Step 2. + * b) If a valid uplink is found, use it. + * c) If the result is an empty node (root not set), break the scan. + * d) If we already returned the left node, break the scan. + * + * 2) Check the right. + * a) If we already returned the right node, proceed to Step 3. + * b) If it is a valid uplink, use it. + * c) Do Step 1 from the right node. + * + * 3) Back up through the parents until we encounter find a parent + * that we're not the right child of. + * + * 4) If there's no right child of that parent, the iteration is finished. + * Otherwise continue to Step 5. + * + * 5) Check to see if the right child is a valid uplink. + * a) If we already returned that child, proceed to Step 6. + * Otherwise, use it. + * + * 6) If the right child of the parent is the parent itself, we've + * already found & returned the end of the Trie, so exit. + * + * 7) Do Step 1 on the parent's right child. + */ + TrieEntry nextEntryImpl(final TrieEntry start, + final TrieEntry previous, final TrieEntry tree) { + + TrieEntry current = start; + + // Only look at the left if this was a recursive or + // the first check, otherwise we know we've already looked + // at the left. + if (previous == null || start != previous.predecessor) { + while (!current.left.isEmpty()) { + // stop traversing if we've already + // returned the left of this node. + if (previous == current.left) { + break; + } + + if (isValidUplink(current.left, current)) { + return current.left; + } + + current = current.left; + } + } + + // If there's no data at all, exit. + if (current.isEmpty()) { + return null; + } + + // If we've already returned the left, + // and the immediate right is null, + // there's only one entry in the Trie + // which is stored at the root. + // + // / ("") <-- root + // \_/ \ + // null <-- 'current' + // + if (current.right == null) { + return null; + } + + // If nothing valid on the left, try the right. + if (previous != current.right) { + // See if it immediately is valid. + if (isValidUplink(current.right, current)) { + return current.right; + } + + // Must search on the right's side if it wasn't initially valid. + return nextEntryImpl(current.right, previous, tree); + } + + // Neither left nor right are valid, find the first parent + // whose child did not come from the right & traverse it. + while (current == current.parent.right) { + // If we're going to traverse to above the subtree, stop. + if (current == tree) { + return null; + } + + current = current.parent; + } + + // If we're on the top of the subtree, we can't go any higher. + if (current == tree) { + return null; + } + + // If there's no right, the parent must be root, so we're done. + if (current.parent.right == null) { + return null; + } + + // If the parent's right points to itself, we've found one. + if (previous != current.parent.right + && isValidUplink(current.parent.right, current.parent)) { + return current.parent.right; + } + + // If the parent's right is itself, there can't be any more nodes. + if (current.parent.right == current.parent) { + return null; + } + + // We need to traverse down the parent's right's path. + return nextEntryImpl(current.parent.right, previous, tree); + } + + /** + * Returns the first entry the {@link Trie} is storing. + *

              + * This is implemented by going always to the left until + * we encounter a valid uplink. That uplink is the first key. + */ + TrieEntry firstEntry() { + // if Trie is empty, no first node. + if (isEmpty()) { + return null; + } + + return followLeft(root); + } + + /** + * Goes left through the tree until it finds a valid node. + */ + TrieEntry followLeft(TrieEntry node) { + while(true) { + TrieEntry child = node.left; + // if we hit root and it didn't have a node, go right instead. + if (child.isEmpty()) { + child = node.right; + } + + if (child.bitIndex <= node.bitIndex) { + return child; + } + + node = child; + } + } + + //----------------------------------------------------------------------- + + public Comparator comparator() { + return getKeyAnalyzer(); + } + + public K firstKey() { + if (size() == 0) { + throw new NoSuchElementException(); + } + return firstEntry().getKey(); + } + + public K lastKey() { + final TrieEntry entry = lastEntry(); + if (entry != null) { + return entry.getKey(); + } + throw new NoSuchElementException(); + } + + public K nextKey(final K key) { + if (key == null) { + throw new NullPointerException(); + } + final TrieEntry entry = getEntry(key); + if (entry != null) { + final TrieEntry nextEntry = nextEntry(entry); + return nextEntry != null ? nextEntry.getKey() : null; + } + return null; + } + + public K previousKey(final K key) { + if (key == null) { + throw new NullPointerException(); + } + final TrieEntry entry = getEntry(key); + if (entry != null) { + final TrieEntry prevEntry = previousEntry(entry); + return prevEntry != null ? prevEntry.getKey() : null; + } + return null; + } + + public OrderedMapIterator mapIterator() { + return new TrieMapIterator(); + } + + public SortedMap prefixMap(final K key) { + return getPrefixMapByBits(key, 0, lengthInBits(key)); + } + + /** + * Returns a view of this {@link Trie} of all elements that are prefixed + * by the number of bits in the given Key. + *

              + * The view that this returns is optimized to have a very efficient + * {@link Iterator}. The {@link SortedMap#firstKey()}, + * {@link SortedMap#lastKey()} & {@link Map#size()} methods must + * iterate over all possible values in order to determine the results. + * This information is cached until the PATRICIA {@link Trie} changes. + * All other methods (except {@link Iterator}) must compare the given + * key to the prefix to ensure that it is within the range of the view. + * The {@link Iterator}'s remove method must also relocate the subtree + * that contains the prefixes if the entry holding the subtree is + * removed or changes. Changing the subtree takes O(K) time. + * + * @param key the key to use in the search + * @param offsetInBits the prefix offset + * @param lengthInBits the number of significant prefix bits + * @return a {@link SortedMap} view of this {@link Trie} with all elements whose + * key is prefixed by the search key + */ + private SortedMap getPrefixMapByBits(final K key, final int offsetInBits, final int lengthInBits) { + + final int offsetLength = offsetInBits + lengthInBits; + if (offsetLength > lengthInBits(key)) { + throw new IllegalArgumentException(offsetInBits + " + " + + lengthInBits + " > " + lengthInBits(key)); + } + + if (offsetLength == 0) { + return this; + } + + return new PrefixRangeMap(key, offsetInBits, lengthInBits); + } + + public SortedMap headMap(final K toKey) { + return new RangeEntryMap(null, toKey); + } + + public SortedMap subMap(final K fromKey, final K toKey) { + return new RangeEntryMap(fromKey, toKey); + } + + public SortedMap tailMap(final K fromKey) { + return new RangeEntryMap(fromKey, null); + } + + /** + * Returns an entry strictly higher than the given key, + * or null if no such entry exists. + */ + TrieEntry higherEntry(final K key) { + // TODO: Cleanup so that we don't actually have to add/remove from the + // tree. (We do it here because there are other well-defined + // functions to perform the search.) + final int lengthInBits = lengthInBits(key); + + if (lengthInBits == 0) { + if (!root.isEmpty()) { + // If data in root, and more after -- return it. + if (size() > 1) { + return nextEntry(root); + } + // If no more after, no higher entry. + return null; + } + // Root is empty & we want something after empty, return first. + return firstEntry(); + } + + final TrieEntry found = getNearestEntryForKey(key, lengthInBits); + if (compareKeys(key, found.key)) { + return nextEntry(found); + } + + final int bitIndex = bitIndex(key, found.key); + if (KeyAnalyzer.isValidBitIndex(bitIndex)) { + final TrieEntry added = new TrieEntry(key, null, bitIndex); + addEntry(added, lengthInBits); + incrementSize(); // must increment because remove will decrement + final TrieEntry ceil = nextEntry(added); + removeEntry(added); + modCount -= 2; // we didn't really modify it. + return ceil; + } else if (KeyAnalyzer.isNullBitKey(bitIndex)) { + if (!root.isEmpty()) { + return firstEntry(); + } else if (size() > 1) { + return nextEntry(firstEntry()); + } else { + return null; + } + } else if (KeyAnalyzer.isEqualBitKey(bitIndex)) { + return nextEntry(found); + } + + // we should have exited above. + throw new IllegalStateException("invalid lookup: " + key); + } + + /** + * Returns a key-value mapping associated with the least key greater + * than or equal to the given key, or null if there is no such key. + */ + TrieEntry ceilingEntry(final K key) { + // Basically: + // Follow the steps of adding an entry, but instead... + // + // - If we ever encounter a situation where we found an equal + // key, we return it immediately. + // + // - If we hit an empty root, return the first iterable item. + // + // - If we have to add a new item, we temporarily add it, + // find the successor to it, then remove the added item. + // + // These steps ensure that the returned value is either the + // entry for the key itself, or the first entry directly after + // the key. + + // TODO: Cleanup so that we don't actually have to add/remove from the + // tree. (We do it here because there are other well-defined + // functions to perform the search.) + final int lengthInBits = lengthInBits(key); + + if (lengthInBits == 0) { + if (!root.isEmpty()) { + return root; + } + return firstEntry(); + } + + final TrieEntry found = getNearestEntryForKey(key, lengthInBits); + if (compareKeys(key, found.key)) { + return found; + } + + final int bitIndex = bitIndex(key, found.key); + if (KeyAnalyzer.isValidBitIndex(bitIndex)) { + final TrieEntry added = new TrieEntry(key, null, bitIndex); + addEntry(added, lengthInBits); + incrementSize(); // must increment because remove will decrement + final TrieEntry ceil = nextEntry(added); + removeEntry(added); + modCount -= 2; // we didn't really modify it. + return ceil; + } else if (KeyAnalyzer.isNullBitKey(bitIndex)) { + if (!root.isEmpty()) { + return root; + } + return firstEntry(); + } else if (KeyAnalyzer.isEqualBitKey(bitIndex)) { + return found; + } + + // we should have exited above. + throw new IllegalStateException("invalid lookup: " + key); + } + + /** + * Returns a key-value mapping associated with the greatest key + * strictly less than the given key, or null if there is no such key. + */ + TrieEntry lowerEntry(final K key) { + // Basically: + // Follow the steps of adding an entry, but instead... + // + // - If we ever encounter a situation where we found an equal + // key, we return it's previousEntry immediately. + // + // - If we hit root (empty or not), return null. + // + // - If we have to add a new item, we temporarily add it, + // find the previousEntry to it, then remove the added item. + // + // These steps ensure that the returned value is always just before + // the key or null (if there was nothing before it). + + // TODO: Cleanup so that we don't actually have to add/remove from the + // tree. (We do it here because there are other well-defined + // functions to perform the search.) + final int lengthInBits = lengthInBits(key); + + if (lengthInBits == 0) { + return null; // there can never be anything before root. + } + + final TrieEntry found = getNearestEntryForKey(key, lengthInBits); + if (compareKeys(key, found.key)) { + return previousEntry(found); + } + + final int bitIndex = bitIndex(key, found.key); + if (KeyAnalyzer.isValidBitIndex(bitIndex)) { + final TrieEntry added = new TrieEntry(key, null, bitIndex); + addEntry(added, lengthInBits); + incrementSize(); // must increment because remove will decrement + final TrieEntry prior = previousEntry(added); + removeEntry(added); + modCount -= 2; // we didn't really modify it. + return prior; + } else if (KeyAnalyzer.isNullBitKey(bitIndex)) { + return null; + } else if (KeyAnalyzer.isEqualBitKey(bitIndex)) { + return previousEntry(found); + } + + // we should have exited above. + throw new IllegalStateException("invalid lookup: " + key); + } + + /** + * Returns a key-value mapping associated with the greatest key + * less than or equal to the given key, or null if there is no such key. + */ + TrieEntry floorEntry(final K key) { + // TODO: Cleanup so that we don't actually have to add/remove from the + // tree. (We do it here because there are other well-defined + // functions to perform the search.) + final int lengthInBits = lengthInBits(key); + + if (lengthInBits == 0) { + if (!root.isEmpty()) { + return root; + } + return null; + } + + final TrieEntry found = getNearestEntryForKey(key, lengthInBits); + if (compareKeys(key, found.key)) { + return found; + } + + final int bitIndex = bitIndex(key, found.key); + if (KeyAnalyzer.isValidBitIndex(bitIndex)) { + final TrieEntry added = new TrieEntry(key, null, bitIndex); + addEntry(added, lengthInBits); + incrementSize(); // must increment because remove will decrement + final TrieEntry floor = previousEntry(added); + removeEntry(added); + modCount -= 2; // we didn't really modify it. + return floor; + } else if (KeyAnalyzer.isNullBitKey(bitIndex)) { + if (!root.isEmpty()) { + return root; + } + return null; + } else if (KeyAnalyzer.isEqualBitKey(bitIndex)) { + return found; + } + + // we should have exited above. + throw new IllegalStateException("invalid lookup: " + key); + } + + /** + * Finds the subtree that contains the prefix. + * + * This is very similar to getR but with the difference that + * we stop the lookup if h.bitIndex > lengthInBits. + */ + TrieEntry subtree(final K prefix, final int offsetInBits, final int lengthInBits) { + TrieEntry current = root.left; + TrieEntry path = root; + while(true) { + if (current.bitIndex <= path.bitIndex || lengthInBits <= current.bitIndex) { + break; + } + + path = current; + if (!isBitSet(prefix, offsetInBits + current.bitIndex, offsetInBits + lengthInBits)) { + current = current.left; + } else { + current = current.right; + } + } + + // Make sure the entry is valid for a subtree. + final TrieEntry entry = current.isEmpty() ? path : current; + + // If entry is root, it can't be empty. + if (entry.isEmpty()) { + return null; + } + + final int endIndexInBits = offsetInBits + lengthInBits; + + // if root && length of root is less than length of lookup, + // there's nothing. + // (this prevents returning the whole subtree if root has an empty + // string and we want to lookup things with "\0") + if (entry == root && lengthInBits(entry.getKey()) < endIndexInBits) { + return null; + } + + // Found key's length-th bit differs from our key + // which means it cannot be the prefix... + if (isBitSet(prefix, endIndexInBits - 1, endIndexInBits) + != isBitSet(entry.key, lengthInBits - 1, lengthInBits(entry.key))) { + return null; + } + + // ... or there are less than 'length' equal bits + final int bitIndex = getKeyAnalyzer().bitIndex(prefix, offsetInBits, lengthInBits, + entry.key, 0, lengthInBits(entry.getKey())); + + if (bitIndex >= 0 && bitIndex < lengthInBits) { + return null; + } + + return entry; + } + + /** + * Returns the last entry the {@link Trie} is storing. + * + *

              This is implemented by going always to the right until + * we encounter a valid uplink. That uplink is the last key. + */ + TrieEntry lastEntry() { + return followRight(root.left); + } + + /** + * Traverses down the right path until it finds an uplink. + */ + TrieEntry followRight(TrieEntry node) { + // if Trie is empty, no last entry. + if (node.right == null) { + return null; + } + + // Go as far right as possible, until we encounter an uplink. + while (node.right.bitIndex > node.bitIndex) { + node = node.right; + } + + return node.right; + } + + /** + * Returns the node lexicographically before the given node (or null if none). + * + * This follows four simple branches: + * - If the uplink that returned us was a right uplink: + * - If predecessor's left is a valid uplink from predecessor, return it. + * - Else, follow the right path from the predecessor's left. + * - If the uplink that returned us was a left uplink: + * - Loop back through parents until we encounter a node where + * node != node.parent.left. + * - If node.parent.left is uplink from node.parent: + * - If node.parent.left is not root, return it. + * - If it is root & root isEmpty, return null. + * - If it is root & root !isEmpty, return root. + * - If node.parent.left is not uplink from node.parent: + * - Follow right path for first right child from node.parent.left + * + * @param start the start entry + */ + TrieEntry previousEntry(final TrieEntry start) { + if (start.predecessor == null) { + throw new IllegalArgumentException("must have come from somewhere!"); + } + + if (start.predecessor.right == start) { + if (isValidUplink(start.predecessor.left, start.predecessor)) { + return start.predecessor.left; + } + return followRight(start.predecessor.left); + } + TrieEntry node = start.predecessor; + while (node.parent != null && node == node.parent.left) { + node = node.parent; + } + + if (node.parent == null) { // can be null if we're looking up root. + return null; + } + + if (isValidUplink(node.parent.left, node.parent)) { + if (node.parent.left == root) { + if (root.isEmpty()) { + return null; + } + return root; + + } + return node.parent.left; + } + return followRight(node.parent.left); + } + + /** + * Returns the entry lexicographically after the given entry. + * If the given entry is null, returns the first node. + * + * This will traverse only within the subtree. If the given node + * is not within the subtree, this will have undefined results. + */ + TrieEntry nextEntryInSubtree(final TrieEntry node, + final TrieEntry parentOfSubtree) { + if (node == null) { + return firstEntry(); + } + return nextEntryImpl(node.predecessor, node, parentOfSubtree); + } + + /** + * Returns true if 'next' is a valid uplink coming from 'from'. + */ + static boolean isValidUplink(final TrieEntry next, final TrieEntry from) { + return next != null && next.bitIndex <= from.bitIndex && !next.isEmpty(); + } + + /** + * A {@link Reference} allows us to return something through a Method's + * argument list. An alternative would be to an Array with a length of + * one (1) but that leads to compiler warnings. Computationally and memory + * wise there's no difference (except for the need to load the + * {@link Reference} Class but that happens only once). + */ + private static class Reference { + + private E item; + + public void set(final E item) { + this.item = item; + } + + public E get() { + return item; + } + } + + /** + * A {@link Trie} is a set of {@link TrieEntry} nodes. + */ + protected static class TrieEntry extends BasicEntry { + + private static final long serialVersionUID = 4596023148184140013L; + + /** The index this entry is comparing. */ + protected int bitIndex; + + /** The parent of this entry. */ + protected TrieEntry parent; + + /** The left child of this entry. */ + protected TrieEntry left; + + /** The right child of this entry. */ + protected TrieEntry right; + + /** The entry who uplinks to this entry. */ + protected TrieEntry predecessor; + + public TrieEntry(final K key, final V value, final int bitIndex) { + super(key, value); + + this.bitIndex = bitIndex; + + this.parent = null; + this.left = this; + this.right = null; + this.predecessor = this; + } + + /** + * Whether or not the entry is storing a key. + * Only the root can potentially be empty, all other + * nodes must have a key. + */ + public boolean isEmpty() { + return key == null; + } + + /** + * Neither the left nor right child is a loopback. + */ + public boolean isInternalNode() { + return left != this && right != this; + } + + /** + * Either the left or right child is a loopback. + */ + public boolean isExternalNode() { + return !isInternalNode(); + } + + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + + if (bitIndex == -1) { + buffer.append("RootEntry("); + } else { + buffer.append("Entry("); + } + + buffer.append("key=").append(getKey()).append(" [").append(bitIndex).append("], "); + buffer.append("value=").append(getValue()).append(", "); + //buffer.append("bitIndex=").append(bitIndex).append(", "); + + if (parent != null) { + if (parent.bitIndex == -1) { + buffer.append("parent=").append("ROOT"); + } else { + buffer.append("parent=").append(parent.getKey()).append(" [").append(parent.bitIndex).append("]"); + } + } else { + buffer.append("parent=").append("null"); + } + buffer.append(", "); + + if (left != null) { + if (left.bitIndex == -1) { + buffer.append("left=").append("ROOT"); + } else { + buffer.append("left=").append(left.getKey()).append(" [").append(left.bitIndex).append("]"); + } + } else { + buffer.append("left=").append("null"); + } + buffer.append(", "); + + if (right != null) { + if (right.bitIndex == -1) { + buffer.append("right=").append("ROOT"); + } else { + buffer.append("right=").append(right.getKey()).append(" [").append(right.bitIndex).append("]"); + } + } else { + buffer.append("right=").append("null"); + } + buffer.append(", "); + + if (predecessor != null) { + if(predecessor.bitIndex == -1) { + buffer.append("predecessor=").append("ROOT"); + } else { + buffer.append("predecessor=").append(predecessor.getKey()).append(" ["). + append(predecessor.bitIndex).append("]"); + } + } + + buffer.append(")"); + return buffer.toString(); + } + } + + + /** + * This is a entry set view of the {@link Trie} as returned by {@link Map#entrySet()}. + */ + private class EntrySet extends AbstractSet> { + + @Override + public Iterator> iterator() { + return new EntryIterator(); + } + + @Override + public boolean contains(final Object o) { + if (!(o instanceof Map.Entry)) { + return false; + } + + final TrieEntry candidate = getEntry(((Map.Entry)o).getKey()); + return candidate != null && candidate.equals(o); + } + + @Override + public boolean remove(final Object obj) { + if (obj instanceof Map.Entry == false) { + return false; + } + if (contains(obj) == false) { + return false; + } + final Map.Entry entry = (Map.Entry) obj; + AbstractPatriciaTrie.this.remove(entry.getKey()); + return true; + } + + @Override + public int size() { + return AbstractPatriciaTrie.this.size(); + } + + @Override + public void clear() { + AbstractPatriciaTrie.this.clear(); + } + + /** + * An {@link Iterator} that returns {@link Entry} Objects. + */ + private class EntryIterator extends TrieIterator> { + public Map.Entry next() { + return nextEntry(); + } + } + } + + /** + * This is a key set view of the {@link Trie} as returned by {@link Map#keySet()}. + */ + private class KeySet extends AbstractSet { + + @Override + public Iterator iterator() { + return new KeyIterator(); + } + + @Override + public int size() { + return AbstractPatriciaTrie.this.size(); + } + + @Override + public boolean contains(final Object o) { + return containsKey(o); + } + + @Override + public boolean remove(final Object o) { + final int size = size(); + AbstractPatriciaTrie.this.remove(o); + return size != size(); + } + + @Override + public void clear() { + AbstractPatriciaTrie.this.clear(); + } + + /** + * An {@link Iterator} that returns Key Objects. + */ + private class KeyIterator extends TrieIterator { + public K next() { + return nextEntry().getKey(); + } + } + } + + /** + * This is a value view of the {@link Trie} as returned by {@link Map#values()}. + */ + private class Values extends AbstractCollection { + + @Override + public Iterator iterator() { + return new ValueIterator(); + } + + @Override + public int size() { + return AbstractPatriciaTrie.this.size(); + } + + @Override + public boolean contains(final Object o) { + return containsValue(o); + } + + @Override + public void clear() { + AbstractPatriciaTrie.this.clear(); + } + + @Override + public boolean remove(final Object o) { + for (final Iterator it = iterator(); it.hasNext(); ) { + final V value = it.next(); + if (compare(value, o)) { + it.remove(); + return true; + } + } + return false; + } + + /** + * An {@link Iterator} that returns Value Objects. + */ + private class ValueIterator extends TrieIterator { + public V next() { + return nextEntry().getValue(); + } + } + } + + /** + * An iterator for the entries. + */ + abstract class TrieIterator implements Iterator { + + /** For fast-fail. */ + protected int expectedModCount = AbstractPatriciaTrie.this.modCount; + + protected TrieEntry next; // the next node to return + protected TrieEntry current; // the current entry we're on + + /** + * Starts iteration from the root. + */ + protected TrieIterator() { + next = AbstractPatriciaTrie.this.nextEntry(null); + } + + /** + * Starts iteration at the given entry. + */ + protected TrieIterator(final TrieEntry firstEntry) { + next = firstEntry; + } + + /** + * Returns the next {@link TrieEntry}. + */ + protected TrieEntry nextEntry() { + if (expectedModCount != AbstractPatriciaTrie.this.modCount) { + throw new ConcurrentModificationException(); + } + + final TrieEntry e = next; + if (e == null) { + throw new NoSuchElementException(); + } + + next = findNext(e); + current = e; + return e; + } + + /** + * @see PatriciaTrie#nextEntry(TrieEntry) + */ + protected TrieEntry findNext(final TrieEntry prior) { + return AbstractPatriciaTrie.this.nextEntry(prior); + } + + public boolean hasNext() { + return next != null; + } + + public void remove() { + if (current == null) { + throw new IllegalStateException(); + } + + if (expectedModCount != AbstractPatriciaTrie.this.modCount) { + throw new ConcurrentModificationException(); + } + + final TrieEntry node = current; + current = null; + AbstractPatriciaTrie.this.removeEntry(node); + + expectedModCount = AbstractPatriciaTrie.this.modCount; + } + } + + /** + * An {@link OrderedMapIterator} for a {@link Trie}. + */ + private class TrieMapIterator extends TrieIterator implements OrderedMapIterator { + + protected TrieEntry previous; // the previous node to return + + public K next() { + return nextEntry().getKey(); + } + + public K getKey() { + if (current == null) { + throw new IllegalStateException(); + } + return current.getKey(); + } + + public V getValue() { + if (current == null) { + throw new IllegalStateException(); + } + return current.getValue(); + } + + public V setValue(final V value) { + if (current == null) { + throw new IllegalStateException(); + } + return current.setValue(value); + } + + public boolean hasPrevious() { + return previous != null; + } + + public K previous() { + return previousEntry().getKey(); + } + + @Override + protected TrieEntry nextEntry() { + final TrieEntry nextEntry = super.nextEntry(); + previous = nextEntry; + return nextEntry; + } + + protected TrieEntry previousEntry() { + if (expectedModCount != AbstractPatriciaTrie.this.modCount) { + throw new ConcurrentModificationException(); + } + + final TrieEntry e = previous; + if (e == null) { + throw new NoSuchElementException(); + } + + previous = AbstractPatriciaTrie.this.previousEntry(e); + next = current; + current = e; + return current; + } + + } + + /** + * A range view of the {@link Trie}. + */ + private abstract class RangeMap extends AbstractMap + implements SortedMap { + + /** The {@link #entrySet()} view. */ + private transient volatile Set> entrySet; + + /** + * Creates and returns an {@link #entrySet()} view of the {@link RangeMap}. + */ + protected abstract Set> createEntrySet(); + + /** + * Returns the FROM Key. + */ + protected abstract K getFromKey(); + + /** + * Whether or not the {@link #getFromKey()} is in the range. + */ + protected abstract boolean isFromInclusive(); + + /** + * Returns the TO Key. + */ + protected abstract K getToKey(); + + /** + * Whether or not the {@link #getToKey()} is in the range. + */ + protected abstract boolean isToInclusive(); + + public Comparator comparator() { + return AbstractPatriciaTrie.this.comparator(); + } + + @Override + public boolean containsKey(final Object key) { + if (!inRange(castKey(key))) { + return false; + } + + return AbstractPatriciaTrie.this.containsKey(key); + } + + @Override + public V remove(final Object key) { + if (!inRange(castKey(key))) { + return null; + } + + return AbstractPatriciaTrie.this.remove(key); + } + + @Override + public V get(final Object key) { + if (!inRange(castKey(key))) { + return null; + } + + return AbstractPatriciaTrie.this.get(key); + } + + @Override + public V put(final K key, final V value) { + if (!inRange(key)) { + throw new IllegalArgumentException("Key is out of range: " + key); + } + return AbstractPatriciaTrie.this.put(key, value); + } + + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = createEntrySet(); + } + return entrySet; + } + + public SortedMap subMap(final K fromKey, final K toKey) { + if (!inRange2(fromKey)) { + throw new IllegalArgumentException("FromKey is out of range: " + fromKey); + } + + if (!inRange2(toKey)) { + throw new IllegalArgumentException("ToKey is out of range: " + toKey); + } + + return createRangeMap(fromKey, isFromInclusive(), toKey, isToInclusive()); + } + + public SortedMap headMap(final K toKey) { + if (!inRange2(toKey)) { + throw new IllegalArgumentException("ToKey is out of range: " + toKey); + } + return createRangeMap(getFromKey(), isFromInclusive(), toKey, isToInclusive()); + } + + public SortedMap tailMap(final K fromKey) { + if (!inRange2(fromKey)) { + throw new IllegalArgumentException("FromKey is out of range: " + fromKey); + } + return createRangeMap(fromKey, isFromInclusive(), getToKey(), isToInclusive()); + } + + /** + * Returns true if the provided key is greater than TO and less than FROM. + */ + protected boolean inRange(final K key) { + final K fromKey = getFromKey(); + final K toKey = getToKey(); + + return (fromKey == null || inFromRange(key, false)) && (toKey == null || inToRange(key, false)); + } + + /** + * This form allows the high endpoint (as well as all legit keys). + */ + protected boolean inRange2(final K key) { + final K fromKey = getFromKey(); + final K toKey = getToKey(); + + return (fromKey == null || inFromRange(key, false)) && (toKey == null || inToRange(key, true)); + } + + /** + * Returns true if the provided key is in the FROM range of the {@link RangeMap}. + */ + protected boolean inFromRange(final K key, final boolean forceInclusive) { + final K fromKey = getFromKey(); + final boolean fromInclusive = isFromInclusive(); + + final int ret = getKeyAnalyzer().compare(key, fromKey); + if (fromInclusive || forceInclusive) { + return ret >= 0; + } + return ret > 0; + } + + /** + * Returns true if the provided key is in the TO range of the {@link RangeMap}. + */ + protected boolean inToRange(final K key, final boolean forceInclusive) { + final K toKey = getToKey(); + final boolean toInclusive = isToInclusive(); + + final int ret = getKeyAnalyzer().compare(key, toKey); + if (toInclusive || forceInclusive) { + return ret <= 0; + } + return ret < 0; + } + + /** + * Creates and returns a sub-range view of the current {@link RangeMap}. + */ + protected abstract SortedMap createRangeMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive); + } + + /** + * A {@link RangeMap} that deals with {@link Entry}s. + */ + private class RangeEntryMap extends RangeMap { + + /** The key to start from, null if the beginning. */ + private final K fromKey; + + /** The key to end at, null if till the end. */ + private final K toKey; + + /** Whether or not the 'from' is inclusive. */ + private final boolean fromInclusive; + + /** Whether or not the 'to' is inclusive. */ + private final boolean toInclusive; + + /** + * Creates a {@link RangeEntryMap} with the fromKey included and + * the toKey excluded from the range. + */ + protected RangeEntryMap(final K fromKey, final K toKey) { + this(fromKey, true, toKey, false); + } + + /** + * Creates a {@link RangeEntryMap}. + */ + protected RangeEntryMap(final K fromKey, final boolean fromInclusive, + final K toKey, final boolean toInclusive) { + + if (fromKey == null && toKey == null) { + throw new IllegalArgumentException("must have a from or to!"); + } + + if (fromKey != null && toKey != null && getKeyAnalyzer().compare(fromKey, toKey) > 0) { + throw new IllegalArgumentException("fromKey > toKey"); + } + + this.fromKey = fromKey; + this.fromInclusive = fromInclusive; + this.toKey = toKey; + this.toInclusive = toInclusive; + } + + public K firstKey() { + Map.Entry e = null; + if (fromKey == null) { + e = firstEntry(); + } else { + if (fromInclusive) { + e = ceilingEntry(fromKey); + } else { + e = higherEntry(fromKey); + } + } + + final K first = e != null ? e.getKey() : null; + if (e == null || toKey != null && !inToRange(first, false)) { + throw new NoSuchElementException(); + } + return first; + } + + public K lastKey() { + Map.Entry e; + if (toKey == null) { + e = lastEntry(); + } else { + if (toInclusive) { + e = floorEntry(toKey); + } else { + e = lowerEntry(toKey); + } + } + + final K last = e != null ? e.getKey() : null; + if (e == null || fromKey != null && !inFromRange(last, false)) { + throw new NoSuchElementException(); + } + return last; + } + + @Override + protected Set> createEntrySet() { + return new RangeEntrySet(this); + } + + @Override + public K getFromKey() { + return fromKey; + } + + @Override + public K getToKey() { + return toKey; + } + + @Override + public boolean isFromInclusive() { + return fromInclusive; + } + + @Override + public boolean isToInclusive() { + return toInclusive; + } + + @Override + protected SortedMap createRangeMap(final K fromKey, final boolean fromInclusive, + final K toKey, final boolean toInclusive) { + return new RangeEntryMap(fromKey, fromInclusive, toKey, toInclusive); + } + } + + /** + * A {@link Set} view of a {@link RangeMap}. + */ + private class RangeEntrySet extends AbstractSet> { + + private final RangeMap delegate; + + private transient int size = -1; + + private transient int expectedModCount; + + /** + * Creates a {@link RangeEntrySet}. + */ + public RangeEntrySet(final RangeMap delegate) { + if (delegate == null) { + throw new NullPointerException("delegate"); + } + + this.delegate = delegate; + } + + @Override + public Iterator> iterator() { + final K fromKey = delegate.getFromKey(); + final K toKey = delegate.getToKey(); + + TrieEntry first = null; + if (fromKey == null) { + first = firstEntry(); + } else { + first = ceilingEntry(fromKey); + } + + TrieEntry last = null; + if (toKey != null) { + last = ceilingEntry(toKey); + } + + return new EntryIterator(first, last); + } + + @Override + public int size() { + if (size == -1 || expectedModCount != AbstractPatriciaTrie.this.modCount) { + size = 0; + + for (final Iterator it = iterator(); it.hasNext(); it.next()) { + ++size; + } + + expectedModCount = AbstractPatriciaTrie.this.modCount; + } + return size; + } + + @Override + public boolean isEmpty() { + return !iterator().hasNext(); + } + + @SuppressWarnings("unchecked") + @Override + public boolean contains(final Object o) { + if (!(o instanceof Map.Entry)) { + return false; + } + + final Map.Entry entry = (Map.Entry) o; + final K key = entry.getKey(); + if (!delegate.inRange(key)) { + return false; + } + + final TrieEntry node = getEntry(key); + return node != null && compare(node.getValue(), entry.getValue()); + } + + @SuppressWarnings("unchecked") + @Override + public boolean remove(final Object o) { + if (!(o instanceof Map.Entry)) { + return false; + } + + final Map.Entry entry = (Map.Entry) o; + final K key = entry.getKey(); + if (!delegate.inRange(key)) { + return false; + } + + final TrieEntry node = getEntry(key); + if (node != null && compare(node.getValue(), entry.getValue())) { + removeEntry(node); + return true; + } + return false; + } + + /** + * An {@link Iterator} for {@link RangeEntrySet}s. + */ + private final class EntryIterator extends TrieIterator> { + + private final K excludedKey; + + /** + * Creates a {@link EntryIterator}. + */ + private EntryIterator(final TrieEntry first, final TrieEntry last) { + super(first); + this.excludedKey = last != null ? last.getKey() : null; + } + + @Override + public boolean hasNext() { + return next != null && !compare(next.key, excludedKey); + } + + public Map.Entry next() { + if (next == null || compare(next.key, excludedKey)) { + throw new NoSuchElementException(); + } + return nextEntry(); + } + } + } + + /** + * A submap used for prefix views over the {@link Trie}. + */ + private class PrefixRangeMap extends RangeMap { + + private final K prefix; + + private final int offsetInBits; + + private final int lengthInBits; + + private K fromKey = null; + + private K toKey = null; + + private transient int expectedModCount = 0; + + private int size = -1; + + /** + * Creates a {@link PrefixRangeMap}. + */ + private PrefixRangeMap(final K prefix, final int offsetInBits, final int lengthInBits) { + this.prefix = prefix; + this.offsetInBits = offsetInBits; + this.lengthInBits = lengthInBits; + } + + /** + * This method does two things. It determines the FROM + * and TO range of the {@link PrefixRangeMap} and the number + * of elements in the range. This method must be called every + * time the {@link Trie} has changed. + */ + private int fixup() { + // The trie has changed since we last found our toKey / fromKey + if (size == - 1 || AbstractPatriciaTrie.this.modCount != expectedModCount) { + final Iterator> it = super.entrySet().iterator(); + size = 0; + + Map.Entry entry = null; + if (it.hasNext()) { + entry = it.next(); + size = 1; + } + + fromKey = entry == null ? null : entry.getKey(); + if (fromKey != null) { + final TrieEntry prior = previousEntry((TrieEntry)entry); + fromKey = prior == null ? null : prior.getKey(); + } + + toKey = fromKey; + + while (it.hasNext()) { + ++size; + entry = it.next(); + } + + toKey = entry == null ? null : entry.getKey(); + + if (toKey != null) { + entry = nextEntry((TrieEntry)entry); + toKey = entry == null ? null : entry.getKey(); + } + + expectedModCount = AbstractPatriciaTrie.this.modCount; + } + + return size; + } + + public K firstKey() { + fixup(); + + Map.Entry e = null; + if (fromKey == null) { + e = firstEntry(); + } else { + e = higherEntry(fromKey); + } + + final K first = e != null ? e.getKey() : null; + if (e == null || !getKeyAnalyzer().isPrefix(prefix, offsetInBits, lengthInBits, first)) { + throw new NoSuchElementException(); + } + + return first; + } + + public K lastKey() { + fixup(); + + Map.Entry e = null; + if (toKey == null) { + e = lastEntry(); + } else { + e = lowerEntry(toKey); + } + + final K last = e != null ? e.getKey() : null; + if (e == null || !getKeyAnalyzer().isPrefix(prefix, offsetInBits, lengthInBits, last)) { + throw new NoSuchElementException(); + } + + return last; + } + + /** + * Returns true if this {@link PrefixRangeMap}'s key is a prefix of the provided key. + */ + @Override + protected boolean inRange(final K key) { + return getKeyAnalyzer().isPrefix(prefix, offsetInBits, lengthInBits, key); + } + + /** + * Same as {@link #inRange(Object)}. + */ + @Override + protected boolean inRange2(final K key) { + return inRange(key); + } + + /** + * Returns true if the provided Key is in the FROM range of the {@link PrefixRangeMap}. + */ + @Override + protected boolean inFromRange(final K key, final boolean forceInclusive) { + return getKeyAnalyzer().isPrefix(prefix, offsetInBits, lengthInBits, key); + } + + /** + * Returns true if the provided Key is in the TO range of the {@link PrefixRangeMap}. + */ + @Override + protected boolean inToRange(final K key, final boolean forceInclusive) { + return getKeyAnalyzer().isPrefix(prefix, offsetInBits, lengthInBits, key); + } + + @Override + protected Set> createEntrySet() { + return new PrefixRangeEntrySet(this); + } + + @Override + public K getFromKey() { + return fromKey; + } + + @Override + public K getToKey() { + return toKey; + } + + @Override + public boolean isFromInclusive() { + return false; + } + + @Override + public boolean isToInclusive() { + return false; + } + + @Override + protected SortedMap createRangeMap(final K fromKey, final boolean fromInclusive, + final K toKey, final boolean toInclusive) { + return new RangeEntryMap(fromKey, fromInclusive, toKey, toInclusive); + } + } + + /** + * A prefix {@link RangeEntrySet} view of the {@link Trie}. + */ + private final class PrefixRangeEntrySet extends RangeEntrySet { + + private final PrefixRangeMap delegate; + + private TrieEntry prefixStart; + + private int expectedModCount = 0; + + /** + * Creates a {@link PrefixRangeEntrySet}. + */ + public PrefixRangeEntrySet(final PrefixRangeMap delegate) { + super(delegate); + this.delegate = delegate; + } + + @Override + public int size() { + return delegate.fixup(); + } + + @Override + public Iterator> iterator() { + if (AbstractPatriciaTrie.this.modCount != expectedModCount) { + prefixStart = subtree(delegate.prefix, delegate.offsetInBits, delegate.lengthInBits); + expectedModCount = AbstractPatriciaTrie.this.modCount; + } + + if (prefixStart == null) { + final Set> empty = Collections.emptySet(); + return empty.iterator(); + } else if (delegate.lengthInBits > prefixStart.bitIndex) { + return new SingletonIterator(prefixStart); + } else { + return new EntryIterator(prefixStart, delegate.prefix, delegate.offsetInBits, delegate.lengthInBits); + } + } + + /** + * An {@link Iterator} that holds a single {@link TrieEntry}. + */ + private final class SingletonIterator implements Iterator> { + + private final TrieEntry entry; + + private int hit = 0; + + public SingletonIterator(final TrieEntry entry) { + this.entry = entry; + } + + public boolean hasNext() { + return hit == 0; + } + + public Map.Entry next() { + if (hit != 0) { + throw new NoSuchElementException(); + } + + ++hit; + return entry; + } + + public void remove() { + if (hit != 1) { + throw new IllegalStateException(); + } + + ++hit; + AbstractPatriciaTrie.this.removeEntry(entry); + } + } + + /** + * An {@link Iterator} for iterating over a prefix search. + */ + private final class EntryIterator extends TrieIterator> { + + // values to reset the subtree if we remove it. + private final K prefix; + private final int offset; + private final int lengthInBits; + private boolean lastOne; + + private TrieEntry subtree; // the subtree to search within + + /** + * Starts iteration at the given entry & search only + * within the given subtree. + */ + EntryIterator(final TrieEntry startScan, final K prefix, + final int offset, final int lengthInBits) { + subtree = startScan; + next = AbstractPatriciaTrie.this.followLeft(startScan); + this.prefix = prefix; + this.offset = offset; + this.lengthInBits = lengthInBits; + } + + public Map.Entry next() { + final Map.Entry entry = nextEntry(); + if (lastOne) { + next = null; + } + return entry; + } + + @Override + protected TrieEntry findNext(final TrieEntry prior) { + return AbstractPatriciaTrie.this.nextEntryInSubtree(prior, subtree); + } + + @Override + public void remove() { + // If the current entry we're removing is the subtree + // then we need to find a new subtree parent. + boolean needsFixing = false; + final int bitIdx = subtree.bitIndex; + if (current == subtree) { + needsFixing = true; + } + + super.remove(); + + // If the subtree changed its bitIndex or we + // removed the old subtree, get a new one. + if (bitIdx != subtree.bitIndex || needsFixing) { + subtree = subtree(prefix, offset, lengthInBits); + } + + // If the subtree's bitIndex is less than the + // length of our prefix, it's the last item + // in the prefix tree. + if (lengthInBits >= subtree.bitIndex) { + lastOne = true; + } + } + } + } + + //----------------------------------------------------------------------- + + /** + * Reads the content of the stream. + */ + @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect + private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException{ + stream.defaultReadObject(); + root = new TrieEntry(null, null, -1); + int size = stream.readInt(); + for(int i = 0; i < size; i++){ + K k = (K) stream.readObject(); + V v = (V) stream.readObject(); + put(k, v); + } + } + + /** + * Writes the content to the stream for serialization. + */ + private void writeObject(final ObjectOutputStream stream) throws IOException{ + stream.defaultWriteObject(); + stream.writeInt(this.size()); + for (final Entry entry : entrySet()) { + stream.writeObject(entry.getKey()); + stream.writeObject(entry.getValue()); + } + } + +} diff --git a/src/org/apache/commons/collections4/trie/KeyAnalyzer.java b/src/org/apache/commons/collections4/trie/KeyAnalyzer.java new file mode 100644 index 0000000..b009bc1 --- /dev/null +++ b/src/org/apache/commons/collections4/trie/KeyAnalyzer.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.trie; + +import java.io.Serializable; +import java.util.Comparator; + +/** + * Defines the interface to analyze {@link org.apache.commons.collections4.Trie Trie} keys on a bit level. + * {@link KeyAnalyzer}'s methods return the length of the key in bits, whether or not a bit is set, + * and bits per element in the key. + *

              + * Additionally, a method determines if a key is a prefix of another + * key and returns the bit index where one key is different from another + * key (if the key and found key are equal than the return value is + * {@link #EQUAL_BIT_KEY}). + * + * @since 4.0 + * @version $Id: KeyAnalyzer.java 1491621 2013-06-10 22:05:38Z tn $ + */ +public abstract class KeyAnalyzer implements Comparator, Serializable { + + /** Serialization version */ + private static final long serialVersionUID = -20497563720380683L; + + /** + * Returned by {@link #bitIndex(Object, int, int, Object, int, int)} + * if key's bits are all 0. + */ + public static final int NULL_BIT_KEY = -1; + + /** + * Returned by {@link #bitIndex(Object, int, int, Object, int, int)} if key and found key are equal. + * This is a very very specific case and shouldn't happen on a regular basis. + */ + public static final int EQUAL_BIT_KEY = -2; + + public static final int OUT_OF_BOUNDS_BIT_KEY = -3; + + /** + * Returns true if bitIndex is a {@link KeyAnalyzer#OUT_OF_BOUNDS_BIT_KEY}. + */ + static boolean isOutOfBoundsIndex(final int bitIndex) { + return bitIndex == OUT_OF_BOUNDS_BIT_KEY; + } + + /** + * Returns true if bitIndex is a {@link KeyAnalyzer#EQUAL_BIT_KEY}. + */ + static boolean isEqualBitKey(final int bitIndex) { + return bitIndex == EQUAL_BIT_KEY; + } + + /** + * Returns true if bitIndex is a {@link KeyAnalyzer#NULL_BIT_KEY}. + */ + static boolean isNullBitKey(final int bitIndex) { + return bitIndex == NULL_BIT_KEY; + } + + /** + * Returns true if the given bitIndex is valid. + * Indices are considered valid if they're between 0 and {@link Integer#MAX_VALUE} + */ + static boolean isValidBitIndex(final int bitIndex) { + return bitIndex >= 0; + } + + /** + * Returns the number of bits per element in the key. + * This is only useful for variable-length keys, such as Strings. + * + * @return the number of bits per element + */ + public abstract int bitsPerElement(); + + /** + * Returns the length of the Key in bits. + * + * @param key the key + * @return the bit length of the key + */ + public abstract int lengthInBits(K key); + + /** + * Returns whether or not a bit is set. + * + * @param key the key to check, may not be null + * @param bitIndex the bit index to check + * @param lengthInBits the maximum key length in bits to check + * @return {@code true} if the bit is set in the given key and + * {@code bitIndex} < {@code lengthInBits}, {@code false} otherwise. + */ + public abstract boolean isBitSet(K key, int bitIndex, int lengthInBits); + + /** + * Returns the n-th different bit between key and other. This starts the comparison in + * key at 'offsetInBits' and goes for 'lengthInBits' bits, and compares to the other key starting + * at 'otherOffsetInBits' and going for 'otherLengthInBits' bits. + * + * @param key the key to use + * @param offsetInBits the bit offset in the key + * @param lengthInBits the maximum key length in bits to use + * @param other the other key to use + * @param otherOffsetInBits the bit offset in the other key + * @param otherLengthInBits the maximum key length in bits for the other key + * @return the bit index where the key and other first differ + */ + public abstract int bitIndex(K key, int offsetInBits, int lengthInBits, + K other, int otherOffsetInBits, int otherLengthInBits); + + /** + * Determines whether or not the given prefix (from offset to length) is a prefix of the given key. + * + * @param prefix the prefix to check + * @param offsetInBits the bit offset in the key + * @param lengthInBits the maximum key length in bits to use + * @param key the key to check + * @return {@code true} if this is a valid prefix for the given key + */ + public abstract boolean isPrefix(K prefix, int offsetInBits, int lengthInBits, K key); + + @SuppressWarnings("unchecked") + public int compare(final K o1, final K o2) { + if (o1 == null) { + return o2 == null ? 0 : -1; + } else if (o2 == null) { + return 1; + } + + return ((Comparable) o1).compareTo(o2); + } + +} diff --git a/src/org/apache/commons/collections4/trie/PatriciaTrie.java b/src/org/apache/commons/collections4/trie/PatriciaTrie.java new file mode 100644 index 0000000..530fd81 --- /dev/null +++ b/src/org/apache/commons/collections4/trie/PatriciaTrie.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.trie; + +import java.util.Map; + +import org.apache.commons.collections4.trie.analyzer.StringKeyAnalyzer; + +/** + * Implementation of a PATRICIA Trie (Practical Algorithm to Retrieve Information + * Coded in Alphanumeric). + *

              + * A PATRICIA {@link Trie} is a compressed {@link Trie}. Instead of storing + * all data at the edges of the {@link Trie} (and having empty internal nodes), + * PATRICIA stores data in every node. This allows for very efficient traversal, + * insert, delete, predecessor, successor, prefix, range, and {@link #select(Object)} + * operations. All operations are performed at worst in O(K) time, where K + * is the number of bits in the largest item in the tree. In practice, + * operations actually take O(A(K)) time, where A(K) is the average number of + * bits of all items in the tree. + *

              + * Most importantly, PATRICIA requires very few comparisons to keys while + * doing any operation. While performing a lookup, each comparison (at most + * K of them, described above) will perform a single bit comparison against + * the given key, instead of comparing the entire key to another key. + *

              + * The {@link Trie} can return operations in lexicographical order using the + * 'prefixMap', 'submap', or 'iterator' methods. The {@link Trie} can also + * scan for items that are 'bitwise' (using an XOR metric) by the 'select' method. + * Bitwise closeness is determined by the {@link KeyAnalyzer} returning true or + * false for a bit being set or not in a given key. + *

              + * This PATRICIA {@link Trie} supports both variable length & fixed length + * keys. Some methods, such as {@link #prefixMap(Object)} are suited only + * to variable length keys. + * + * @see Radix Tree + * @see PATRICIA + * @see Crit-Bit Tree + * @since 4.0 + * @version $Id: PatriciaTrie.java 1543928 2013-11-20 20:15:35Z tn $ + */ +public class PatriciaTrie extends AbstractPatriciaTrie { + + private static final long serialVersionUID = 4446367780901817838L; + + public PatriciaTrie() { + super(new StringKeyAnalyzer()); + } + + public PatriciaTrie(final Map m) { + super(new StringKeyAnalyzer(), m); + } + +} diff --git a/src/org/apache/commons/collections4/trie/UnmodifiableTrie.java b/src/org/apache/commons/collections4/trie/UnmodifiableTrie.java new file mode 100644 index 0000000..91a54fd --- /dev/null +++ b/src/org/apache/commons/collections4/trie/UnmodifiableTrie.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.trie; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.apache.commons.collections4.OrderedMapIterator; +import org.apache.commons.collections4.Trie; +import org.apache.commons.collections4.Unmodifiable; +import org.apache.commons.collections4.iterators.UnmodifiableOrderedMapIterator; + +/** + * An unmodifiable {@link Trie}. + * + * @since 4.0 + * @version $Id: UnmodifiableTrie.java 1686855 2015-06-22 13:00:27Z tn $ + */ +public class UnmodifiableTrie implements Trie, Serializable, Unmodifiable { + + /** Serialization version */ + private static final long serialVersionUID = -7156426030315945159L; + + private final Trie delegate; + + /** + * Factory method to create a unmodifiable trie. + * + * @param the key type + * @param the value type + * @param trie the trie to decorate, must not be null + * @return a new unmodifiable trie + * @throws NullPointerException if trie is null + */ + public static Trie unmodifiableTrie(final Trie trie) { + if (trie instanceof Unmodifiable) { + @SuppressWarnings("unchecked") // safe to upcast + final Trie tmpTrie = (Trie) trie; + return tmpTrie; + } + return new UnmodifiableTrie(trie); + } + + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies). + * + * @param trie the trie to decorate, must not be null + * @throws NullPointerException if trie is null + */ + public UnmodifiableTrie(final Trie trie) { + if (trie == null) { + throw new NullPointerException("Trie must not be null"); + } + @SuppressWarnings("unchecked") // safe to upcast + final Trie tmpTrie = (Trie) trie; + this.delegate = tmpTrie; + } + + //----------------------------------------------------------------------- + + public Set> entrySet() { + return Collections.unmodifiableSet(delegate.entrySet()); + } + + public Set keySet() { + return Collections.unmodifiableSet(delegate.keySet()); + } + + public Collection values() { + return Collections.unmodifiableCollection(delegate.values()); + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public boolean containsKey(final Object key) { + return delegate.containsKey(key); + } + + public boolean containsValue(final Object value) { + return delegate.containsValue(value); + } + + public V get(final Object key) { + return delegate.get(key); + } + + public boolean isEmpty() { + return delegate.isEmpty(); + } + + public V put(final K key, final V value) { + throw new UnsupportedOperationException(); + } + + public void putAll(final Map m) { + throw new UnsupportedOperationException(); + } + + public V remove(final Object key) { + throw new UnsupportedOperationException(); + } + + public int size() { + return delegate.size(); + } + + public K firstKey() { + return delegate.firstKey(); + } + + public SortedMap headMap(final K toKey) { + return Collections.unmodifiableSortedMap(delegate.headMap(toKey)); + } + + public K lastKey() { + return delegate.lastKey(); + } + + public SortedMap subMap(final K fromKey, final K toKey) { + return Collections.unmodifiableSortedMap(delegate.subMap(fromKey, toKey)); + } + + public SortedMap tailMap(final K fromKey) { + return Collections.unmodifiableSortedMap(delegate.tailMap(fromKey)); + } + + public SortedMap prefixMap(final K key) { + return Collections.unmodifiableSortedMap(delegate.prefixMap(key)); + } + + public Comparator comparator() { + return delegate.comparator(); + } + + //----------------------------------------------------------------------- + public OrderedMapIterator mapIterator() { + final OrderedMapIterator it = delegate.mapIterator(); + return UnmodifiableOrderedMapIterator.unmodifiableOrderedMapIterator(it); + } + + public K nextKey(K key) { + return delegate.nextKey(key); + } + + public K previousKey(K key) { + return delegate.previousKey(key); + } + + //----------------------------------------------------------------------- + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + return delegate.equals(obj); + } + + @Override + public String toString() { + return delegate.toString(); + } + +} diff --git a/src/org/apache/commons/collections4/trie/analyzer/StringKeyAnalyzer.java b/src/org/apache/commons/collections4/trie/analyzer/StringKeyAnalyzer.java new file mode 100644 index 0000000..beeb515 --- /dev/null +++ b/src/org/apache/commons/collections4/trie/analyzer/StringKeyAnalyzer.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections4.trie.analyzer; + +import org.apache.commons.collections4.trie.KeyAnalyzer; + +/** + * An {@link KeyAnalyzer} for {@link String}s. + * + * @since 4.0 + * @version $Id: StringKeyAnalyzer.java 1543168 2013-11-18 21:22:43Z ggregory $ + */ +public class StringKeyAnalyzer extends KeyAnalyzer { + + private static final long serialVersionUID = -7032449491269434877L; + + /** A singleton instance of {@link StringKeyAnalyzer}. */ + public static final StringKeyAnalyzer INSTANCE = new StringKeyAnalyzer(); + + /** The number of bits per {@link Character}. */ + public static final int LENGTH = Character.SIZE; + + /** A bit mask where the first bit is 1 and the others are zero. */ + private static final int MSB = 0x8000; + + /** Returns a bit mask where the given bit is set. */ + private static int mask(final int bit) { + return MSB >>> bit; + } + + @Override + public int bitsPerElement() { + return LENGTH; + } + + @Override + public int lengthInBits(final String key) { + return key != null ? key.length() * LENGTH : 0; + } + + @Override + public int bitIndex(final String key, final int offsetInBits, final int lengthInBits, + final String other, final int otherOffsetInBits, final int otherLengthInBits) { + + boolean allNull = true; + + if (offsetInBits % LENGTH != 0 || otherOffsetInBits % LENGTH != 0 + || lengthInBits % LENGTH != 0 || otherLengthInBits % LENGTH != 0) { + throw new IllegalArgumentException("The offsets and lengths must be at Character boundaries"); + } + + final int beginIndex1 = offsetInBits / LENGTH; + final int beginIndex2 = otherOffsetInBits / LENGTH; + + final int endIndex1 = beginIndex1 + lengthInBits / LENGTH; + final int endIndex2 = beginIndex2 + otherLengthInBits / LENGTH; + + final int length = Math.max(endIndex1, endIndex2); + + // Look at each character, and if they're different + // then figure out which bit makes the difference + // and return it. + char k = 0, f = 0; + for(int i = 0; i < length; i++) { + final int index1 = beginIndex1 + i; + final int index2 = beginIndex2 + i; + + if (index1 >= endIndex1) { + k = 0; + } else { + k = key.charAt(index1); + } + + if (other == null || index2 >= endIndex2) { + f = 0; + } else { + f = other.charAt(index2); + } + + if (k != f) { + final int x = k ^ f; + return i * LENGTH + Integer.numberOfLeadingZeros(x) - LENGTH; + } + + if (k != 0) { + allNull = false; + } + } + + // All bits are 0 + if (allNull) { + return KeyAnalyzer.NULL_BIT_KEY; + } + + // Both keys are equal + return KeyAnalyzer.EQUAL_BIT_KEY; + } + + @Override + public boolean isBitSet(final String key, final int bitIndex, final int lengthInBits) { + if (key == null || bitIndex >= lengthInBits) { + return false; + } + + final int index = bitIndex / LENGTH; + final int bit = bitIndex % LENGTH; + + return (key.charAt(index) & mask(bit)) != 0; + } + + @Override + public boolean isPrefix(final String prefix, final int offsetInBits, + final int lengthInBits, final String key) { + if (offsetInBits % LENGTH != 0 || lengthInBits % LENGTH != 0) { + throw new IllegalArgumentException( + "Cannot determine prefix outside of Character boundaries"); + } + + final String s1 = prefix.substring(offsetInBits / LENGTH, lengthInBits / LENGTH); + return key.startsWith(s1); + } +} diff --git a/src/org/apache/commons/collections4/trie/analyzer/package-info.java b/src/org/apache/commons/collections4/trie/analyzer/package-info.java new file mode 100644 index 0000000..5eeb5d3 --- /dev/null +++ b/src/org/apache/commons/collections4/trie/analyzer/package-info.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains various {@link org.apache.commons.collections4.trie.KeyAnalyzer} implementations. + * + * @version $Id: package-info.java 1491615 2013-06-10 21:46:19Z tn $ + */ +package org.apache.commons.collections4.trie.analyzer; diff --git a/src/org/apache/commons/collections4/trie/package-info.java b/src/org/apache/commons/collections4/trie/package-info.java new file mode 100644 index 0000000..cd0a298 --- /dev/null +++ b/src/org/apache/commons/collections4/trie/package-info.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package contains implementations of the + * {@link org.apache.commons.collections4.Trie Trie} interface. + *

              + * The implementations are in the form of direct implementations and decorators. + * A decorator wraps another implementation of the interface to add some + * specific additional functionality. + *

              + * The following implementations are provided in the package: + *

                + *
              • PatriciaTrie - an implementation of a PATRICIA trie + *
              + *

              + * The following decorators are provided: + *

                + *
              • Unmodifiable - ensures the collection cannot be altered + *
              + * + * @version $Id: package-info.java 1493523 2013-06-16 15:56:35Z tn $ + */ +package org.apache.commons.collections4.trie; diff --git a/src/org/apache/commons/lang3/AnnotationUtils.java b/src/org/apache/commons/lang3/AnnotationUtils.java new file mode 100644 index 0000000..81bd0f0 --- /dev/null +++ b/src/org/apache/commons/lang3/AnnotationUtils.java @@ -0,0 +1,368 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + *

              Helper methods for working with {@link Annotation} instances.

              + * + *

              This class contains various utility methods that make working with + * annotations simpler.

              + * + *

              {@link Annotation} instances are always proxy objects; unfortunately + * dynamic proxies cannot be depended upon to know how to implement certain + * methods in the same manner as would be done by "natural" {@link Annotation}s. + * The methods presented in this class can be used to avoid that possibility. It + * is of course also possible for dynamic proxies to actually delegate their + * e.g. {@link Annotation#equals(Object)}/{@link Annotation#hashCode()}/ + * {@link Annotation#toString()} implementations to {@link AnnotationUtils}.

              + * + *

              #ThreadSafe#

              + * + * @since 3.0 + */ +public class AnnotationUtils { + + /** + * A style that prints annotations as recommended. + */ + private static final ToStringStyle TO_STRING_STYLE = new ToStringStyle() { + /** Serialization version */ + private static final long serialVersionUID = 1L; + + { + setDefaultFullDetail(true); + setArrayContentDetail(true); + setUseClassName(true); + setUseShortClassName(true); + setUseIdentityHashCode(false); + setContentStart("("); + setContentEnd(")"); + setFieldSeparator(", "); + setArrayStart("["); + setArrayEnd("]"); + } + + /** + * {@inheritDoc} + */ + @Override + protected String getShortClassName(final java.lang.Class cls) { + Class annotationType = null; + for (final Class iface : ClassUtils.getAllInterfaces(cls)) { + if (Annotation.class.isAssignableFrom(iface)) { + @SuppressWarnings("unchecked") // OK because we just checked the assignability + final + Class found = (Class) iface; + annotationType = found; + break; + } + } + return new StringBuilder(annotationType == null ? StringUtils.EMPTY : annotationType.getName()) + .insert(0, '@').toString(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, Object value) { + if (value instanceof Annotation) { + value = AnnotationUtils.toString((Annotation) value); + } + super.appendDetail(buffer, fieldName, value); + } + + }; + + /** + *

              {@code AnnotationUtils} instances should NOT be constructed in + * standard programming. Instead, the class should be used statically.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public AnnotationUtils() { + } + + //----------------------------------------------------------------------- + /** + *

              Checks if two annotations are equal using the criteria for equality + * presented in the {@link Annotation#equals(Object)} API docs.

              + * + * @param a1 the first Annotation to compare, {@code null} returns + * {@code false} unless both are {@code null} + * @param a2 the second Annotation to compare, {@code null} returns + * {@code false} unless both are {@code null} + * @return {@code true} if the two annotations are {@code equal} or both + * {@code null} + */ + public static boolean equals(final Annotation a1, final Annotation a2) { + if (a1 == a2) { + return true; + } + if (a1 == null || a2 == null) { + return false; + } + final Class type = a1.annotationType(); + final Class type2 = a2.annotationType(); + Validate.notNull(type, "Annotation %s with null annotationType()", a1); + Validate.notNull(type2, "Annotation %s with null annotationType()", a2); + if (!type.equals(type2)) { + return false; + } + try { + for (final Method m : type.getDeclaredMethods()) { + if (m.getParameterTypes().length == 0 + && isValidAnnotationMemberType(m.getReturnType())) { + final Object v1 = m.invoke(a1); + final Object v2 = m.invoke(a2); + if (!memberEquals(m.getReturnType(), v1, v2)) { + return false; + } + } + } + } catch (final IllegalAccessException | InvocationTargetException ex) { + return false; + } + return true; + } + + /** + *

              Generate a hash code for the given annotation using the algorithm + * presented in the {@link Annotation#hashCode()} API docs.

              + * + * @param a the Annotation for a hash code calculation is desired, not + * {@code null} + * @return the calculated hash code + * @throws RuntimeException if an {@code Exception} is encountered during + * annotation member access + * @throws IllegalStateException if an annotation method invocation returns + * {@code null} + */ + public static int hashCode(final Annotation a) { + int result = 0; + final Class type = a.annotationType(); + for (final Method m : type.getDeclaredMethods()) { + try { + final Object value = m.invoke(a); + if (value == null) { + throw new IllegalStateException( + String.format("Annotation method %s returned null", m)); + } + result += hashMember(m.getName(), value); + } catch (final RuntimeException ex) { + throw ex; + } catch (final Exception ex) { + throw new RuntimeException(ex); + } + } + return result; + } + + /** + *

              Generate a string representation of an Annotation, as suggested by + * {@link Annotation#toString()}.

              + * + * @param a the annotation of which a string representation is desired + * @return the standard string representation of an annotation, not + * {@code null} + */ + public static String toString(final Annotation a) { + final ToStringBuilder builder = new ToStringBuilder(a, TO_STRING_STYLE); + for (final Method m : a.annotationType().getDeclaredMethods()) { + if (m.getParameterTypes().length > 0) { + continue; //wtf? + } + try { + builder.append(m.getName(), m.invoke(a)); + } catch (final RuntimeException ex) { + throw ex; + } catch (final Exception ex) { + throw new RuntimeException(ex); + } + } + return builder.build(); + } + + /** + *

              Checks if the specified type is permitted as an annotation member.

              + * + *

              The Java language specification only permits certain types to be used + * in annotations. These include {@link String}, {@link Class}, primitive + * types, {@link Annotation}, {@link Enum}, and single-dimensional arrays of + * these types.

              + * + * @param type the type to check, {@code null} + * @return {@code true} if the type is a valid type to use in an annotation + */ + public static boolean isValidAnnotationMemberType(Class type) { + if (type == null) { + return false; + } + if (type.isArray()) { + type = type.getComponentType(); + } + return type.isPrimitive() || type.isEnum() || type.isAnnotation() + || String.class.equals(type) || Class.class.equals(type); + } + + //besides modularity, this has the advantage of autoboxing primitives: + /** + * Helper method for generating a hash code for a member of an annotation. + * + * @param name the name of the member + * @param value the value of the member + * @return a hash code for this member + */ + private static int hashMember(final String name, final Object value) { + final int part1 = name.hashCode() * 127; + if (value.getClass().isArray()) { + return part1 ^ arrayMemberHash(value.getClass().getComponentType(), value); + } + if (value instanceof Annotation) { + return part1 ^ hashCode((Annotation) value); + } + return part1 ^ value.hashCode(); + } + + /** + * Helper method for checking whether two objects of the given type are + * equal. This method is used to compare the parameters of two annotation + * instances. + * + * @param type the type of the objects to be compared + * @param o1 the first object + * @param o2 the second object + * @return a flag whether these objects are equal + */ + private static boolean memberEquals(final Class type, final Object o1, final Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + if (type.isArray()) { + return arrayMemberEquals(type.getComponentType(), o1, o2); + } + if (type.isAnnotation()) { + return equals((Annotation) o1, (Annotation) o2); + } + return o1.equals(o2); + } + + /** + * Helper method for comparing two objects of an array type. + * + * @param componentType the component type of the array + * @param o1 the first object + * @param o2 the second object + * @return a flag whether these objects are equal + */ + private static boolean arrayMemberEquals(final Class componentType, final Object o1, final Object o2) { + if (componentType.isAnnotation()) { + return annotationArrayMemberEquals((Annotation[]) o1, (Annotation[]) o2); + } + if (componentType.equals(Byte.TYPE)) { + return Arrays.equals((byte[]) o1, (byte[]) o2); + } + if (componentType.equals(Short.TYPE)) { + return Arrays.equals((short[]) o1, (short[]) o2); + } + if (componentType.equals(Integer.TYPE)) { + return Arrays.equals((int[]) o1, (int[]) o2); + } + if (componentType.equals(Character.TYPE)) { + return Arrays.equals((char[]) o1, (char[]) o2); + } + if (componentType.equals(Long.TYPE)) { + return Arrays.equals((long[]) o1, (long[]) o2); + } + if (componentType.equals(Float.TYPE)) { + return Arrays.equals((float[]) o1, (float[]) o2); + } + if (componentType.equals(Double.TYPE)) { + return Arrays.equals((double[]) o1, (double[]) o2); + } + if (componentType.equals(Boolean.TYPE)) { + return Arrays.equals((boolean[]) o1, (boolean[]) o2); + } + return Arrays.equals((Object[]) o1, (Object[]) o2); + } + + /** + * Helper method for comparing two arrays of annotations. + * + * @param a1 the first array + * @param a2 the second array + * @return a flag whether these arrays are equal + */ + private static boolean annotationArrayMemberEquals(final Annotation[] a1, final Annotation[] a2) { + if (a1.length != a2.length) { + return false; + } + for (int i = 0; i < a1.length; i++) { + if (!equals(a1[i], a2[i])) { + return false; + } + } + return true; + } + + /** + * Helper method for generating a hash code for an array. + * + * @param componentType the component type of the array + * @param o the array + * @return a hash code for the specified array + */ + private static int arrayMemberHash(final Class componentType, final Object o) { + if (componentType.equals(Byte.TYPE)) { + return Arrays.hashCode((byte[]) o); + } + if (componentType.equals(Short.TYPE)) { + return Arrays.hashCode((short[]) o); + } + if (componentType.equals(Integer.TYPE)) { + return Arrays.hashCode((int[]) o); + } + if (componentType.equals(Character.TYPE)) { + return Arrays.hashCode((char[]) o); + } + if (componentType.equals(Long.TYPE)) { + return Arrays.hashCode((long[]) o); + } + if (componentType.equals(Float.TYPE)) { + return Arrays.hashCode((float[]) o); + } + if (componentType.equals(Double.TYPE)) { + return Arrays.hashCode((double[]) o); + } + if (componentType.equals(Boolean.TYPE)) { + return Arrays.hashCode((boolean[]) o); + } + return Arrays.hashCode((Object[]) o); + } +} diff --git a/src/org/apache/commons/lang3/ArchUtils.java b/src/org/apache/commons/lang3/ArchUtils.java new file mode 100644 index 0000000..249110b --- /dev/null +++ b/src/org/apache/commons/lang3/ArchUtils.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.arch.Processor; + +/** + * An utility class for the os.arch System Property. The class defines methods for + * identifying the architecture of the current JVM. + *

              + * Important: The os.arch System Property returns the architecture used by the JVM + * not of the operating system. + *

              + * @since 3.6 + */ +public class ArchUtils { + + private static final Map ARCH_TO_PROCESSOR; + + static { + ARCH_TO_PROCESSOR = new HashMap<>(); + init(); + } + + private static final void init() { + init_X86_32Bit(); + init_X86_64Bit(); + init_IA64_32Bit(); + init_IA64_64Bit(); + init_PPC_32Bit(); + init_PPC_64Bit(); + } + + private static final void init_X86_32Bit() { + Processor processor = new Processor(Processor.Arch.BIT_32, Processor.Type.X86); + addProcessors(processor, "x86", "i386", "i486", "i586", "i686", "pentium"); + } + + private static final void init_X86_64Bit() { + Processor processor = new Processor(Processor.Arch.BIT_64, Processor.Type.X86); + addProcessors(processor, "x86_64", "amd64", "em64t", "universal"); + } + + private static final void init_IA64_32Bit() { + Processor processor = new Processor(Processor.Arch.BIT_32, Processor.Type.IA_64); + addProcessors(processor, "ia64_32", "ia64n"); + } + + private static final void init_IA64_64Bit() { + Processor processor = new Processor(Processor.Arch.BIT_64, Processor.Type.IA_64); + addProcessors(processor, "ia64", "ia64w"); + } + + private static final void init_PPC_32Bit() { + Processor processor = new Processor(Processor.Arch.BIT_32, Processor.Type.PPC); + addProcessors(processor, "ppc", "power", "powerpc", "power_pc", "power_rs"); + } + + private static final void init_PPC_64Bit() { + Processor processor = new Processor(Processor.Arch.BIT_64, Processor.Type.PPC); + addProcessors(processor, "ppc64", "power64", "powerpc64", "power_pc64", "power_rs64"); + } + + /** + * Adds the given {@link Processor} with the given key {@link String} to the map. + * + * @param key The key as {@link String}. + * @param processor The {@link Processor} to add. + * @throws IllegalStateException If the key already exists. + */ + private static final void addProcessor(String key, Processor processor) throws IllegalStateException { + if (!ARCH_TO_PROCESSOR.containsKey(key)) { + ARCH_TO_PROCESSOR.put(key, processor); + } else { + String msg = "Key " + key + " already exists in processor map"; + throw new IllegalStateException(msg); + } + } + + /** + * Adds the given {@link Processor} with the given keys to the map. + * + * @param keys The keys. + * @param processor The {@link Processor} to add. + * @throws IllegalStateException If the key already exists. + */ + private static final void addProcessors(Processor processor, String... keys) throws IllegalStateException { + for (String key : keys) { + addProcessor(key, processor); + } + } + + /** + * Returns a {@link Processor} object of the current JVM. + * + *

              + * Important: The os.arch System Property returns the architecture used by the JVM + * not of the operating system. + *

              + * + * @return A {@link Processor} when supported, else null. + */ + public static final Processor getProcessor() { + return getProcessor(SystemUtils.OS_ARCH); + } + + /** + * Returns a {@link Processor} object the given value {@link String}. The {@link String} must be + * like a value returned by the os.arch System Property. + * + * @param value A {@link String} like a value returned by the os.arch System Property. + * @return A {@link Processor} when it exists, else null. + */ + public static final Processor getProcessor(String value) { + return ARCH_TO_PROCESSOR.get(value); + } + +} diff --git a/src/org/apache/commons/lang3/ArrayUtils.java b/src/org/apache/commons/lang3/ArrayUtils.java new file mode 100644 index 0000000..ac241e2 --- /dev/null +++ b/src/org/apache/commons/lang3/ArrayUtils.java @@ -0,0 +1,8450 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.commons.lang3.mutable.MutableInt; + +/** + *

              Operations on arrays, primitive arrays (like {@code int[]}) and + * primitive wrapper arrays (like {@code Integer[]}). + * + *

              This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} + * array input. However, an Object array that contains a {@code null} + * element may throw an exception. Each method documents its behaviour. + * + *

              #ThreadSafe# + * @since 2.0 + */ +public class ArrayUtils { + + /** + * An empty immutable {@code Object} array. + */ + public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + /** + * An empty immutable {@code Class} array. + */ + public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + /** + * An empty immutable {@code String} array. + */ + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + /** + * An empty immutable {@code long} array. + */ + public static final long[] EMPTY_LONG_ARRAY = new long[0]; + /** + * An empty immutable {@code Long} array. + */ + public static final Long[] EMPTY_LONG_OBJECT_ARRAY = new Long[0]; + /** + * An empty immutable {@code int} array. + */ + public static final int[] EMPTY_INT_ARRAY = new int[0]; + /** + * An empty immutable {@code Integer} array. + */ + public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = new Integer[0]; + /** + * An empty immutable {@code short} array. + */ + public static final short[] EMPTY_SHORT_ARRAY = new short[0]; + /** + * An empty immutable {@code Short} array. + */ + public static final Short[] EMPTY_SHORT_OBJECT_ARRAY = new Short[0]; + /** + * An empty immutable {@code byte} array. + */ + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + /** + * An empty immutable {@code Byte} array. + */ + public static final Byte[] EMPTY_BYTE_OBJECT_ARRAY = new Byte[0]; + /** + * An empty immutable {@code double} array. + */ + public static final double[] EMPTY_DOUBLE_ARRAY = new double[0]; + /** + * An empty immutable {@code Double} array. + */ + public static final Double[] EMPTY_DOUBLE_OBJECT_ARRAY = new Double[0]; + /** + * An empty immutable {@code float} array. + */ + public static final float[] EMPTY_FLOAT_ARRAY = new float[0]; + /** + * An empty immutable {@code Float} array. + */ + public static final Float[] EMPTY_FLOAT_OBJECT_ARRAY = new Float[0]; + /** + * An empty immutable {@code boolean} array. + */ + public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0]; + /** + * An empty immutable {@code Boolean} array. + */ + public static final Boolean[] EMPTY_BOOLEAN_OBJECT_ARRAY = new Boolean[0]; + /** + * An empty immutable {@code char} array. + */ + public static final char[] EMPTY_CHAR_ARRAY = new char[0]; + /** + * An empty immutable {@code Character} array. + */ + public static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY = new Character[0]; + + /** + * The index value when an element is not found in a list or array: {@code -1}. + * This value is returned by methods in this class and can also be used in comparisons with values returned by + * various method from {@link java.util.List}. + */ + public static final int INDEX_NOT_FOUND = -1; + + /** + *

              ArrayUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as ArrayUtils.clone(new int[] {2}). + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate. + */ + public ArrayUtils() { + super(); + } + + + // NOTE: Cannot use {@code} to enclose text which includes {}, but is OK + + + // Basic methods handling multi-dimensional arrays + //----------------------------------------------------------------------- + /** + *

              Outputs an array as a String, treating {@code null} as an empty array. + * + *

              Multi-dimensional arrays are handled correctly, including + * multi-dimensional primitive arrays. + * + *

              The format is that of Java source code, for example {a,b}. + * + * @param array the array to get a toString for, may be {@code null} + * @return a String representation of the array, '{}' if null array input + */ + public static String toString(final Object array) { + return toString(array, "{}"); + } + + /** + *

              Outputs an array as a String handling {@code null}s. + * + *

              Multi-dimensional arrays are handled correctly, including + * multi-dimensional primitive arrays. + * + *

              The format is that of Java source code, for example {a,b}. + * + * @param array the array to get a toString for, may be {@code null} + * @param stringIfNull the String to return if the array is {@code null} + * @return a String representation of the array + */ + public static String toString(final Object array, final String stringIfNull) { + if (array == null) { + return stringIfNull; + } + return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString(); + } + + /** + *

              Get a hash code for an array handling multi-dimensional arrays correctly. + * + *

              Multi-dimensional primitive arrays are also handled correctly by this method. + * + * @param array the array to get a hash code for, {@code null} returns zero + * @return a hash code for the array + */ + public static int hashCode(final Object array) { + return new HashCodeBuilder().append(array).toHashCode(); + } + + /** + *

              Compares two arrays, using equals(), handling multi-dimensional arrays + * correctly. + * + *

              Multi-dimensional primitive arrays are also handled correctly by this method. + * + * @param array1 the left hand array to compare, may be {@code null} + * @param array2 the right hand array to compare, may be {@code null} + * @return {@code true} if the arrays are equal + * @deprecated this method has been replaced by {@code java.util.Objects.deepEquals(Object, Object)} and will be + * removed from future releases. + */ + @Deprecated + public static boolean isEquals(final Object array1, final Object array2) { + return new EqualsBuilder().append(array1, array2).isEquals(); + } + + // To map + //----------------------------------------------------------------------- + /** + *

              Converts the given array into a {@link java.util.Map}. Each element of the array + * must be either a {@link java.util.Map.Entry} or an Array, containing at least two + * elements, where the first element is used as key and the second as + * value. + * + *

              This method can be used to initialize: + *

              +     * // Create a Map mapping colors.
              +     * Map colorMap = ArrayUtils.toMap(new String[][] {
              +     *     {"RED", "#FF0000"},
              +     *     {"GREEN", "#00FF00"},
              +     *     {"BLUE", "#0000FF"}});
              +     * 
              + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array an array whose elements are either a {@link java.util.Map.Entry} or + * an Array containing at least two elements, may be {@code null} + * @return a {@code Map} that was created from the array + * @throws IllegalArgumentException if one element of this Array is + * itself an Array containing less then two elements + * @throws IllegalArgumentException if the array contains elements other + * than {@link java.util.Map.Entry} and an Array + */ + public static Map toMap(final Object[] array) { + if (array == null) { + return null; + } + final Map map = new HashMap<>((int) (array.length * 1.5)); + for (int i = 0; i < array.length; i++) { + final Object object = array[i]; + if (object instanceof Map.Entry) { + final Map.Entry entry = (Map.Entry) object; + map.put(entry.getKey(), entry.getValue()); + } else if (object instanceof Object[]) { + final Object[] entry = (Object[]) object; + if (entry.length < 2) { + throw new IllegalArgumentException("Array element " + i + ", '" + + object + + "', has a length less than 2"); + } + map.put(entry[0], entry[1]); + } else { + throw new IllegalArgumentException("Array element " + i + ", '" + + object + + "', is neither of type Map.Entry nor an Array"); + } + } + return map; + } + + // Generic array + //----------------------------------------------------------------------- + /** + *

              Create a type-safe generic array. + * + *

              The Java language does not allow an array to be created from a generic type: + * + *

              +    public static <T> T[] createAnArray(int size) {
              +        return new T[size]; // compiler error here
              +    }
              +    public static <T> T[] createAnArray(int size) {
              +        return (T[])new Object[size]; // ClassCastException at runtime
              +    }
              +     * 
              + * + *

              Therefore new arrays of generic types can be created with this method. + * For example, an array of Strings can be created: + * + *

              +    String[] array = ArrayUtils.toArray("1", "2");
              +    String[] emptyArray = ArrayUtils.<String>toArray();
              +     * 
              + * + *

              The method is typically used in scenarios, where the caller itself uses generic types + * that have to be combined into an array. + * + *

              Note, this method makes only sense to provide arguments of the same type so that the + * compiler can deduce the type of the array itself. While it is possible to select the + * type explicitly like in + * Number[] array = ArrayUtils.<Number>toArray(Integer.valueOf(42), Double.valueOf(Math.PI)), + * there is no real advantage when compared to + * new Number[] {Integer.valueOf(42), Double.valueOf(Math.PI)}. + * + * @param the array's element type + * @param items the varargs array items, null allowed + * @return the array, not null unless a null array is passed in + * @since 3.0 + */ + @SafeVarargs + public static T[] toArray(final T... items) { + return items; + } + + // Clone + //----------------------------------------------------------------------- + /** + *

              Shallow clones an array returning a typecast result and handling + * {@code null}. + * + *

              The objects in the array are not cloned, thus there is no special + * handling for multi-dimensional arrays. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param the component type of the array + * @param array the array to shallow clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static T[] clone(final T[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static long[] clone(final long[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static int[] clone(final int[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static short[] clone(final short[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static char[] clone(final char[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static byte[] clone(final byte[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static double[] clone(final double[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static float[] clone(final float[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + /** + *

              Clones an array returning a typecast result and handling + * {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array the array to clone, may be {@code null} + * @return the cloned array, {@code null} if {@code null} input + */ + public static boolean[] clone(final boolean[] array) { + if (array == null) { + return null; + } + return array.clone(); + } + + // nullToEmpty + //----------------------------------------------------------------------- + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + * @param array the array to check for {@code null} or empty + * @param type the class representation of the desired array + * @param the class type + * @return the same array, {@code public static} empty array if {@code null} + * @throws IllegalArgumentException if the type argument is null + * @since 3.5 + */ + public static T[] nullToEmpty(final T[] array, final Class type) { + if (type == null) { + throw new IllegalArgumentException("The type must not be null"); + } + + if (array == null) { + return type.cast(Array.newInstance(type.getComponentType(), 0)); + } + return array; + } + + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Object[] nullToEmpty(final Object[] array) { + if (isEmpty(array)) { + return EMPTY_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 3.2 + */ + public static Class[] nullToEmpty(final Class[] array) { + if (isEmpty(array)) { + return EMPTY_CLASS_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static String[] nullToEmpty(final String[] array) { + if (isEmpty(array)) { + return EMPTY_STRING_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static long[] nullToEmpty(final long[] array) { + if (isEmpty(array)) { + return EMPTY_LONG_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static int[] nullToEmpty(final int[] array) { + if (isEmpty(array)) { + return EMPTY_INT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static short[] nullToEmpty(final short[] array) { + if (isEmpty(array)) { + return EMPTY_SHORT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static char[] nullToEmpty(final char[] array) { + if (isEmpty(array)) { + return EMPTY_CHAR_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static byte[] nullToEmpty(final byte[] array) { + if (isEmpty(array)) { + return EMPTY_BYTE_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static double[] nullToEmpty(final double[] array) { + if (isEmpty(array)) { + return EMPTY_DOUBLE_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static float[] nullToEmpty(final float[] array) { + if (isEmpty(array)) { + return EMPTY_FLOAT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static boolean[] nullToEmpty(final boolean[] array) { + if (isEmpty(array)) { + return EMPTY_BOOLEAN_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Long[] nullToEmpty(final Long[] array) { + if (isEmpty(array)) { + return EMPTY_LONG_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Integer[] nullToEmpty(final Integer[] array) { + if (isEmpty(array)) { + return EMPTY_INTEGER_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Short[] nullToEmpty(final Short[] array) { + if (isEmpty(array)) { + return EMPTY_SHORT_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Character[] nullToEmpty(final Character[] array) { + if (isEmpty(array)) { + return EMPTY_CHARACTER_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Byte[] nullToEmpty(final Byte[] array) { + if (isEmpty(array)) { + return EMPTY_BYTE_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Double[] nullToEmpty(final Double[] array) { + if (isEmpty(array)) { + return EMPTY_DOUBLE_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Float[] nullToEmpty(final Float[] array) { + if (isEmpty(array)) { + return EMPTY_FLOAT_OBJECT_ARRAY; + } + return array; + } + + /** + *

              Defensive programming technique to change a {@code null} + * reference to an empty one. + * + *

              This method returns an empty array for a {@code null} input array. + * + *

              As a memory optimizing technique an empty array passed in will be overridden with + * the empty {@code public static} references in this class. + * + * @param array the array to check for {@code null} or empty + * @return the same array, {@code public static} empty array if {@code null} or empty input + * @since 2.5 + */ + public static Boolean[] nullToEmpty(final Boolean[] array) { + if (isEmpty(array)) { + return EMPTY_BOOLEAN_OBJECT_ARRAY; + } + return array; + } + + // Subarrays + //----------------------------------------------------------------------- + /** + *

              Produces a new array containing the elements between + * the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + *

              The component type of the subarray is always the same as + * that of the input array. Thus, if the input is an array of type + * {@code Date}, the following usage is envisaged: + * + *

              +     * Date[] someDates = (Date[])ArrayUtils.subarray(allDates, 2, 5);
              +     * 
              + * + * @param the component type of the array + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(Object[], int, int) + */ + public static T[] subarray(final T[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + final Class type = array.getClass().getComponentType(); + if (newSize <= 0) { + @SuppressWarnings("unchecked") // OK, because array is of type T + final T[] emptyArray = (T[]) Array.newInstance(type, 0); + return emptyArray; + } + @SuppressWarnings("unchecked") // OK, because array is of type T + final + T[] subarray = (T[]) Array.newInstance(type, newSize); + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code long} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(long[], int, int) + */ + public static long[] subarray(final long[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_LONG_ARRAY; + } + + final long[] subarray = new long[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code int} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(int[], int, int) + */ + public static int[] subarray(final int[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_INT_ARRAY; + } + + final int[] subarray = new int[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code short} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(short[], int, int) + */ + public static short[] subarray(final short[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_SHORT_ARRAY; + } + + final short[] subarray = new short[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code char} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(char[], int, int) + */ + public static char[] subarray(final char[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_CHAR_ARRAY; + } + + final char[] subarray = new char[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code byte} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(byte[], int, int) + */ + public static byte[] subarray(final byte[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_BYTE_ARRAY; + } + + final byte[] subarray = new byte[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code double} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(double[], int, int) + */ + public static double[] subarray(final double[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_DOUBLE_ARRAY; + } + + final double[] subarray = new double[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code float} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(float[], int, int) + */ + public static float[] subarray(final float[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_FLOAT_ARRAY; + } + + final float[] subarray = new float[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + /** + *

              Produces a new {@code boolean} array containing the elements + * between the start and end indices. + * + *

              The start index is inclusive, the end index exclusive. + * Null array input produces null output. + * + * @param array the array + * @param startIndexInclusive the starting index. Undervalue (<0) + * is promoted to 0, overvalue (>array.length) results + * in an empty array. + * @param endIndexExclusive elements up to endIndex-1 are present in the + * returned subarray. Undervalue (< startIndex) produces + * empty array, overvalue (>array.length) is demoted to + * array length. + * @return a new array containing the elements between + * the start and end indices. + * @since 2.1 + * @see Arrays#copyOfRange(boolean[], int, int) + */ + public static boolean[] subarray(final boolean[] array, int startIndexInclusive, int endIndexExclusive) { + if (array == null) { + return null; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive > array.length) { + endIndexExclusive = array.length; + } + final int newSize = endIndexExclusive - startIndexInclusive; + if (newSize <= 0) { + return EMPTY_BOOLEAN_ARRAY; + } + + final boolean[] subarray = new boolean[newSize]; + System.arraycopy(array, startIndexInclusive, subarray, 0, newSize); + return subarray; + } + + // Is same length + //----------------------------------------------------------------------- + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + *

              Any multi-dimensional aspects of the arrays are ignored. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final Object[] array1, final Object[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final long[] array1, final long[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final int[] array1, final int[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final short[] array1, final short[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final char[] array1, final char[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final byte[] array1, final byte[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final double[] array1, final double[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final float[] array1, final float[] array2) { + return getLength(array1) == getLength(array2); + } + + /** + *

              Checks whether two arrays are the same length, treating + * {@code null} arrays as length {@code 0}. + * + * @param array1 the first array, may be {@code null} + * @param array2 the second array, may be {@code null} + * @return {@code true} if length of arrays matches, treating + * {@code null} as an empty array + */ + public static boolean isSameLength(final boolean[] array1, final boolean[] array2) { + return getLength(array1) == getLength(array2); + } + + //----------------------------------------------------------------------- + /** + *

              Returns the length of the specified array. + * This method can deal with {@code Object} arrays and with primitive arrays. + * + *

              If the input array is {@code null}, {@code 0} is returned. + * + *

              +     * ArrayUtils.getLength(null)            = 0
              +     * ArrayUtils.getLength([])              = 0
              +     * ArrayUtils.getLength([null])          = 1
              +     * ArrayUtils.getLength([true, false])   = 2
              +     * ArrayUtils.getLength([1, 2, 3])       = 3
              +     * ArrayUtils.getLength(["a", "b", "c"]) = 3
              +     * 
              + * + * @param array the array to retrieve the length from, may be null + * @return The length of the array, or {@code 0} if the array is {@code null} + * @throws IllegalArgumentException if the object argument is not an array. + * @since 2.1 + */ + public static int getLength(final Object array) { + if (array == null) { + return 0; + } + return Array.getLength(array); + } + + /** + *

              Checks whether two arrays are the same type taking into account + * multi-dimensional arrays. + * + * @param array1 the first array, must not be {@code null} + * @param array2 the second array, must not be {@code null} + * @return {@code true} if type of arrays matches + * @throws IllegalArgumentException if either array is {@code null} + */ + public static boolean isSameType(final Object array1, final Object array2) { + if (array1 == null || array2 == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + return array1.getClass().getName().equals(array2.getClass().getName()); + } + + // Reverse + //----------------------------------------------------------------------- + /** + *

              Reverses the order of the given array. + * + *

              There is no special handling for multi-dimensional arrays. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final Object[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final long[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final int[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final short[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final char[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final byte[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final double[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final float[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              Reverses the order of the given array. + * + *

              This method does nothing for a {@code null} input array. + * + * @param array the array to reverse, may be {@code null} + */ + public static void reverse(final boolean[] array) { + if (array == null) { + return; + } + reverse(array, 0, array.length); + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final boolean[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + boolean tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final byte[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + byte tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final char[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + char tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final double[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + double tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final float[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + float tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final int[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + int tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final long[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + long tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Under value (<0) is promoted to 0, over value (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Under value (< start index) results in no + * change. Over value (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final Object[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + Object tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + /** + *

              + * Reverses the order of the given array in the given range. + * + *

              + * This method does nothing for a {@code null} input array. + * + * @param array + * the array to reverse, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @since 3.2 + */ + public static void reverse(final short[] array, final int startIndexInclusive, final int endIndexExclusive) { + if (array == null) { + return; + } + int i = startIndexInclusive < 0 ? 0 : startIndexInclusive; + int j = Math.min(array.length, endIndexExclusive) - 1; + short tmp; + while (j > i) { + tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + j--; + i++; + } + } + + // Swap + //----------------------------------------------------------------------- + /** + * Swaps two elements in the given array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap(["1", "2", "3"], 0, 2) -> ["3", "2", "1"]
              • + *
              • ArrayUtils.swap(["1", "2", "3"], 0, 0) -> ["1", "2", "3"]
              • + *
              • ArrayUtils.swap(["1", "2", "3"], 1, 0) -> ["2", "1", "3"]
              • + *
              • ArrayUtils.swap(["1", "2", "3"], 0, 5) -> ["1", "2", "3"]
              • + *
              • ArrayUtils.swap(["1", "2", "3"], -1, 1) -> ["2", "1", "3"]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final Object[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given long array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([true, false, true], 0, 2) -> [true, false, true]
              • + *
              • ArrayUtils.swap([true, false, true], 0, 0) -> [true, false, true]
              • + *
              • ArrayUtils.swap([true, false, true], 1, 0) -> [false, true, true]
              • + *
              • ArrayUtils.swap([true, false, true], 0, 5) -> [true, false, true]
              • + *
              • ArrayUtils.swap([true, false, true], -1, 1) -> [false, true, true]
              • + *
              + * + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final long[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given int array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final int[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given short array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final short[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given char array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final char[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given byte array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final byte[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given double array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final double[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given float array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final float[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps two elements in the given boolean array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for a {@code null} or empty input array or for overflow indices. + * Negative indices are promoted to 0(zero).

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
              • + *
              • ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element to swap + * @param offset2 the index of the second element to swap + * @since 3.5 + */ + public static void swap(final boolean[] array, final int offset1, final int offset2) { + if (array == null || array.length == 0) { + return; + } + swap(array, offset1, offset2, 1); + } + + /** + * Swaps a series of elements in the given boolean array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([true, false, true, false], 0, 2, 1) -> [true, false, true, false]
              • + *
              • ArrayUtils.swap([true, false, true, false], 0, 0, 1) -> [true, false, true, false]
              • + *
              • ArrayUtils.swap([true, false, true, false], 0, 2, 2) -> [true, false, true, false]
              • + *
              • ArrayUtils.swap([true, false, true, false], -3, 2, 2) -> [true, false, true, false]
              • + *
              • ArrayUtils.swap([true, false, true, false], 0, 3, 3) -> [false, false, true, true]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final boolean[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final boolean aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + /** + * Swaps a series of elements in the given byte array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 2, 1) -> [3, 2, 1, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 0, 1) -> [1, 2, 3, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 2, 0, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], -3, 2, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 3, 3) -> [4, 2, 3, 1]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final byte[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final byte aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + /** + * Swaps a series of elements in the given char array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 2, 1) -> [3, 2, 1, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 0, 1) -> [1, 2, 3, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 2, 0, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], -3, 2, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 3, 3) -> [4, 2, 3, 1]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final char[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final char aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + /** + * Swaps a series of elements in the given double array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 2, 1) -> [3, 2, 1, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 0, 1) -> [1, 2, 3, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 2, 0, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], -3, 2, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 3, 3) -> [4, 2, 3, 1]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final double[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final double aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + /** + * Swaps a series of elements in the given float array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 2, 1) -> [3, 2, 1, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 0, 1) -> [1, 2, 3, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 2, 0, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], -3, 2, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 3, 3) -> [4, 2, 3, 1]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final float[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final float aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + + } + + /** + * Swaps a series of elements in the given int array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 2, 1) -> [3, 2, 1, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 0, 1) -> [1, 2, 3, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 2, 0, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], -3, 2, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 3, 3) -> [4, 2, 3, 1]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final int[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final int aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + /** + * Swaps a series of elements in the given long array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 2, 1) -> [3, 2, 1, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 0, 1) -> [1, 2, 3, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 2, 0, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], -3, 2, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 3, 3) -> [4, 2, 3, 1]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final long[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final long aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + /** + * Swaps a series of elements in the given array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap(["1", "2", "3", "4"], 0, 2, 1) -> ["3", "2", "1", "4"]
              • + *
              • ArrayUtils.swap(["1", "2", "3", "4"], 0, 0, 1) -> ["1", "2", "3", "4"]
              • + *
              • ArrayUtils.swap(["1", "2", "3", "4"], 2, 0, 2) -> ["3", "4", "1", "2"]
              • + *
              • ArrayUtils.swap(["1", "2", "3", "4"], -3, 2, 2) -> ["3", "4", "1", "2"]
              • + *
              • ArrayUtils.swap(["1", "2", "3", "4"], 0, 3, 3) -> ["4", "2", "3", "1"]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final Object[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final Object aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + /** + * Swaps a series of elements in the given short array. + * + *

              This method does nothing for a {@code null} or empty input array or + * for overflow indices. Negative indices are promoted to 0(zero). If any + * of the sub-arrays to swap falls outside of the given array, then the + * swap is stopped at the end of the array and as many as possible elements + * are swapped.

              + * + * Examples: + *
                + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 2, 1) -> [3, 2, 1, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 0, 1) -> [1, 2, 3, 4]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 2, 0, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], -3, 2, 2) -> [3, 4, 1, 2]
              • + *
              • ArrayUtils.swap([1, 2, 3, 4], 0, 3, 3) -> [4, 2, 3, 1]
              • + *
              + * + * @param array the array to swap, may be {@code null} + * @param offset1 the index of the first element in the series to swap + * @param offset2 the index of the second element in the series to swap + * @param len the number of elements to swap starting with the given indices + * @since 3.5 + */ + public static void swap(final short[] array, int offset1, int offset2, int len) { + if (array == null || array.length == 0 || offset1 >= array.length || offset2 >= array.length) { + return; + } + if (offset1 < 0) { + offset1 = 0; + } + if (offset2 < 0) { + offset2 = 0; + } + if (offset1 == offset2) { + return; + } + len = Math.min(Math.min(len, array.length - offset1), array.length - offset2); + for (int i = 0; i < len; i++, offset1++, offset2++) { + final short aux = array[offset1]; + array[offset1] = array[offset2]; + array[offset2] = aux; + } + } + + // Shift + //----------------------------------------------------------------------- + /** + * Shifts the order of the given array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final Object[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given long array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final long[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given int array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final int[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given short array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final short[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given char array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final char[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given byte array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final byte[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given double array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final double[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given float array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final float[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of the given boolean array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array the array to shift, may be {@code null} + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final boolean[] array, final int offset) { + if (array == null) { + return; + } + shift(array, 0, array.length, offset); + } + + /** + * Shifts the order of a series of elements in the given boolean array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final boolean[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given byte array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final byte[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given char array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final char[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given double array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final double[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given float array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final float[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given int array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final int[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given long array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final long[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final Object[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + /** + * Shifts the order of a series of elements in the given short array. + * + *

              There is no special handling for multi-dimensional arrays. This method + * does nothing for {@code null} or empty input arrays.

              + * + * @param array + * the array to shift, may be {@code null} + * @param startIndexInclusive + * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no + * change. + * @param endIndexExclusive + * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no + * change. Overvalue (>array.length) is demoted to array length. + * @param offset + * The number of positions to rotate the elements. If the offset is larger than the number of elements to + * rotate, than the effective offset is modulo the number of elements to rotate. + * @since 3.5 + */ + public static void shift(final short[] array, int startIndexInclusive, int endIndexExclusive, int offset) { + if (array == null) { + return; + } + if (startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) { + return; + } + if (startIndexInclusive < 0) { + startIndexInclusive = 0; + } + if (endIndexExclusive >= array.length) { + endIndexExclusive = array.length; + } + int n = endIndexExclusive - startIndexInclusive; + if (n <= 1) { + return; + } + offset %= n; + if (offset < 0) { + offset += n; + } + // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity + // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/ + while (n > 1 && offset > 0) { + final int n_offset = n - offset; + + if (offset > n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n - n_offset, n_offset); + n = offset; + offset -= n_offset; + } else if (offset < n_offset) { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + startIndexInclusive += offset; + n = n_offset; + } else { + swap(array, startIndexInclusive, startIndexInclusive + n_offset, offset); + break; + } + } + } + + // IndexOf search + // ---------------------------------------------------------------------- + + // Object IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given object in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param objectToFind the object to find, may be {@code null} + * @return the index of the object within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final Object[] array, final Object objectToFind) { + return indexOf(array, objectToFind, 0); + } + + /** + *

              Finds the index of the given object in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param objectToFind the object to find, may be {@code null} + * @param startIndex the index to start searching at + * @return the index of the object within the array starting at the index, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final Object[] array, final Object objectToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + if (objectToFind == null) { + for (int i = startIndex; i < array.length; i++) { + if (array[i] == null) { + return i; + } + } + } else { + for (int i = startIndex; i < array.length; i++) { + if (objectToFind.equals(array[i])) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given object within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param objectToFind the object to find, may be {@code null} + * @return the last index of the object within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final Object[] array, final Object objectToFind) { + return lastIndexOf(array, objectToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given object in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than + * the array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param objectToFind the object to find, may be {@code null} + * @param startIndex the start index to traverse backwards from + * @return the last index of the object within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final Object[] array, final Object objectToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + if (objectToFind == null) { + for (int i = startIndex; i >= 0; i--) { + if (array[i] == null) { + return i; + } + } + } else if (array.getClass().getComponentType().isInstance(objectToFind)) { + for (int i = startIndex; i >= 0; i--) { + if (objectToFind.equals(array[i])) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the object is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param objectToFind the object to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final Object[] array, final Object objectToFind) { + return indexOf(array, objectToFind) != INDEX_NOT_FOUND; + } + + // long IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final long[] array, final long valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final long[] array, final long valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final long[] array, final long valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final long[] array, final long valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final long[] array, final long valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + // int IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final int[] array, final int valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final int[] array, final int valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final int[] array, final int valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final int[] array, final int valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final int[] array, final int valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + // short IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final short[] array, final short valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final short[] array, final short valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final short[] array, final short valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final short[] array, final short valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final short[] array, final short valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + // char IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + * @since 2.1 + */ + public static int indexOf(final char[] array, final char valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + * @since 2.1 + */ + public static int indexOf(final char[] array, final char valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + * @since 2.1 + */ + public static int lastIndexOf(final char[] array, final char valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + * @since 2.1 + */ + public static int lastIndexOf(final char[] array, final char valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + * @since 2.1 + */ + public static boolean contains(final char[] array, final char valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + // byte IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final byte[] array, final byte valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final byte[] array, final byte valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final byte[] array, final byte valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final byte[] array, final byte valueToFind, int startIndex) { + if (array == null) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final byte[] array, final byte valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + // double IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final double[] array, final double valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value within a given tolerance in the array. + * This method will return the index of the first value which falls between the region + * defined by valueToFind - tolerance and valueToFind + tolerance. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param tolerance tolerance of the search + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final double[] array, final double valueToFind, final double tolerance) { + return indexOf(array, valueToFind, 0, tolerance); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final double[] array, final double valueToFind, int startIndex) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * This method will return the index of the first value which falls between the region + * defined by valueToFind - tolerance and valueToFind + tolerance. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @param tolerance tolerance of the search + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + final double min = valueToFind - tolerance; + final double max = valueToFind + tolerance; + for (int i = startIndex; i < array.length; i++) { + if (array[i] >= min && array[i] <= max) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final double[] array, final double valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value within a given tolerance in the array. + * This method will return the index of the last value which falls between the region + * defined by valueToFind - tolerance and valueToFind + tolerance. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param tolerance tolerance of the search + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final double[] array, final double valueToFind, final double tolerance) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * This method will return the index of the last value which falls between the region + * defined by valueToFind - tolerance and valueToFind + tolerance. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @param tolerance search for value within plus/minus this amount + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + final double min = valueToFind - tolerance; + final double max = valueToFind + tolerance; + for (int i = startIndex; i >= 0; i--) { + if (array[i] >= min && array[i] <= max) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final double[] array, final double valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + /** + *

              Checks if a value falling within the given tolerance is in the + * given array. If the array contains a value within the inclusive range + * defined by (value - tolerance) to (value + tolerance). + * + *

              The method returns {@code false} if a {@code null} array + * is passed in. + * + * @param array the array to search + * @param valueToFind the value to find + * @param tolerance the array contains the tolerance of the search + * @return true if value falling within tolerance is in array + */ + public static boolean contains(final double[] array, final double valueToFind, final double tolerance) { + return indexOf(array, valueToFind, 0, tolerance) != INDEX_NOT_FOUND; + } + + // float IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final float[] array, final float valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final float[] array, final float valueToFind, int startIndex) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final float[] array, final float valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the + * array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final float[] array, final float valueToFind, int startIndex) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final float[] array, final float valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + // boolean IndexOf + //----------------------------------------------------------------------- + /** + *

              Finds the index of the given value in the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int indexOf(final boolean[] array, final boolean valueToFind) { + return indexOf(array, valueToFind, 0); + } + + /** + *

              Finds the index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex is treated as zero. A startIndex larger than the array + * length will return {@link #INDEX_NOT_FOUND} ({@code -1}). + * + * @param array the array to search through for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the index to start searching at + * @return the index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} + * array input + */ + public static int indexOf(final boolean[] array, final boolean valueToFind, int startIndex) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + startIndex = 0; + } + for (int i = startIndex; i < array.length; i++) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Finds the last index of the given value within the array. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) if + * {@code null} array input. + * + * @param array the array to traverse backwards looking for the object, may be {@code null} + * @param valueToFind the object to find + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final boolean[] array, final boolean valueToFind) { + return lastIndexOf(array, valueToFind, Integer.MAX_VALUE); + } + + /** + *

              Finds the last index of the given value in the array starting at the given index. + * + *

              This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array. + * + *

              A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than + * the array length will search from the end of the array. + * + * @param array the array to traverse for looking for the object, may be {@code null} + * @param valueToFind the value to find + * @param startIndex the start index to traverse backwards from + * @return the last index of the value within the array, + * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input + */ + public static int lastIndexOf(final boolean[] array, final boolean valueToFind, int startIndex) { + if (ArrayUtils.isEmpty(array)) { + return INDEX_NOT_FOUND; + } + if (startIndex < 0) { + return INDEX_NOT_FOUND; + } else if (startIndex >= array.length) { + startIndex = array.length - 1; + } + for (int i = startIndex; i >= 0; i--) { + if (valueToFind == array[i]) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Checks if the value is in the given array. + * + *

              The method returns {@code false} if a {@code null} array is passed in. + * + * @param array the array to search through + * @param valueToFind the value to find + * @return {@code true} if the array contains the object + */ + public static boolean contains(final boolean[] array, final boolean valueToFind) { + return indexOf(array, valueToFind) != INDEX_NOT_FOUND; + } + + // Primitive/Object array converters + // ---------------------------------------------------------------------- + + // Character array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Characters to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Character} array, may be {@code null} + * @return a {@code char} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static char[] toPrimitive(final Character[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_CHAR_ARRAY; + } + final char[] result = new char[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].charValue(); + } + return result; + } + + /** + *

              Converts an array of object Character to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Character} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return a {@code char} array, {@code null} if null array input + */ + public static char[] toPrimitive(final Character[] array, final char valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_CHAR_ARRAY; + } + final char[] result = new char[array.length]; + for (int i = 0; i < array.length; i++) { + final Character b = array[i]; + result[i] = (b == null ? valueForNull : b.charValue()); + } + return result; + } + + /** + *

              Converts an array of primitive chars to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code char} array + * @return a {@code Character} array, {@code null} if null array input + */ + public static Character[] toObject(final char[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_CHARACTER_OBJECT_ARRAY; + } + final Character[] result = new Character[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = Character.valueOf(array[i]); + } + return result; + } + + // Long array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Longs to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Long} array, may be {@code null} + * @return a {@code long} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static long[] toPrimitive(final Long[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_LONG_ARRAY; + } + final long[] result = new long[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].longValue(); + } + return result; + } + + /** + *

              Converts an array of object Long to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Long} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return a {@code long} array, {@code null} if null array input + */ + public static long[] toPrimitive(final Long[] array, final long valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_LONG_ARRAY; + } + final long[] result = new long[array.length]; + for (int i = 0; i < array.length; i++) { + final Long b = array[i]; + result[i] = (b == null ? valueForNull : b.longValue()); + } + return result; + } + + /** + *

              Converts an array of primitive longs to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code long} array + * @return a {@code Long} array, {@code null} if null array input + */ + public static Long[] toObject(final long[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_LONG_OBJECT_ARRAY; + } + final Long[] result = new Long[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = Long.valueOf(array[i]); + } + return result; + } + + // Int array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Integers to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Integer} array, may be {@code null} + * @return an {@code int} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static int[] toPrimitive(final Integer[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_INT_ARRAY; + } + final int[] result = new int[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].intValue(); + } + return result; + } + + /** + *

              Converts an array of object Integer to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Integer} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return an {@code int} array, {@code null} if null array input + */ + public static int[] toPrimitive(final Integer[] array, final int valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_INT_ARRAY; + } + final int[] result = new int[array.length]; + for (int i = 0; i < array.length; i++) { + final Integer b = array[i]; + result[i] = (b == null ? valueForNull : b.intValue()); + } + return result; + } + + /** + *

              Converts an array of primitive ints to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array an {@code int} array + * @return an {@code Integer} array, {@code null} if null array input + */ + public static Integer[] toObject(final int[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_INTEGER_OBJECT_ARRAY; + } + final Integer[] result = new Integer[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = Integer.valueOf(array[i]); + } + return result; + } + + // Short array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Shorts to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Short} array, may be {@code null} + * @return a {@code byte} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static short[] toPrimitive(final Short[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_SHORT_ARRAY; + } + final short[] result = new short[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].shortValue(); + } + return result; + } + + /** + *

              Converts an array of object Short to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Short} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return a {@code byte} array, {@code null} if null array input + */ + public static short[] toPrimitive(final Short[] array, final short valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_SHORT_ARRAY; + } + final short[] result = new short[array.length]; + for (int i = 0; i < array.length; i++) { + final Short b = array[i]; + result[i] = (b == null ? valueForNull : b.shortValue()); + } + return result; + } + + /** + *

              Converts an array of primitive shorts to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code short} array + * @return a {@code Short} array, {@code null} if null array input + */ + public static Short[] toObject(final short[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_SHORT_OBJECT_ARRAY; + } + final Short[] result = new Short[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = Short.valueOf(array[i]); + } + return result; + } + + // Byte array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Bytes to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Byte} array, may be {@code null} + * @return a {@code byte} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static byte[] toPrimitive(final Byte[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_BYTE_ARRAY; + } + final byte[] result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].byteValue(); + } + return result; + } + + /** + *

              Converts an array of object Bytes to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Byte} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return a {@code byte} array, {@code null} if null array input + */ + public static byte[] toPrimitive(final Byte[] array, final byte valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_BYTE_ARRAY; + } + final byte[] result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + final Byte b = array[i]; + result[i] = (b == null ? valueForNull : b.byteValue()); + } + return result; + } + + /** + *

              Converts an array of primitive bytes to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code byte} array + * @return a {@code Byte} array, {@code null} if null array input + */ + public static Byte[] toObject(final byte[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_BYTE_OBJECT_ARRAY; + } + final Byte[] result = new Byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = Byte.valueOf(array[i]); + } + return result; + } + + // Double array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Doubles to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Double} array, may be {@code null} + * @return a {@code double} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static double[] toPrimitive(final Double[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_DOUBLE_ARRAY; + } + final double[] result = new double[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].doubleValue(); + } + return result; + } + + /** + *

              Converts an array of object Doubles to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Double} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return a {@code double} array, {@code null} if null array input + */ + public static double[] toPrimitive(final Double[] array, final double valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_DOUBLE_ARRAY; + } + final double[] result = new double[array.length]; + for (int i = 0; i < array.length; i++) { + final Double b = array[i]; + result[i] = (b == null ? valueForNull : b.doubleValue()); + } + return result; + } + + /** + *

              Converts an array of primitive doubles to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code double} array + * @return a {@code Double} array, {@code null} if null array input + */ + public static Double[] toObject(final double[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_DOUBLE_OBJECT_ARRAY; + } + final Double[] result = new Double[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = Double.valueOf(array[i]); + } + return result; + } + + // Float array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Floats to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Float} array, may be {@code null} + * @return a {@code float} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static float[] toPrimitive(final Float[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_FLOAT_ARRAY; + } + final float[] result = new float[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].floatValue(); + } + return result; + } + + /** + *

              Converts an array of object Floats to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Float} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return a {@code float} array, {@code null} if null array input + */ + public static float[] toPrimitive(final Float[] array, final float valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_FLOAT_ARRAY; + } + final float[] result = new float[array.length]; + for (int i = 0; i < array.length; i++) { + final Float b = array[i]; + result[i] = (b == null ? valueForNull : b.floatValue()); + } + return result; + } + + /** + *

              Converts an array of primitive floats to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code float} array + * @return a {@code Float} array, {@code null} if null array input + */ + public static Float[] toObject(final float[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_FLOAT_OBJECT_ARRAY; + } + final Float[] result = new Float[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = Float.valueOf(array[i]); + } + return result; + } + + /** + *

              Create an array of primitive type from an array of wrapper types. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array an array of wrapper object + * @return an array of the corresponding primitive type, or the original array + * @since 3.5 + */ + public static Object toPrimitive(final Object array) { + if (array == null) { + return null; + } + final Class ct = array.getClass().getComponentType(); + final Class pt = ClassUtils.wrapperToPrimitive(ct); + if(Integer.TYPE.equals(pt)) { + return toPrimitive((Integer[]) array); + } + if(Long.TYPE.equals(pt)) { + return toPrimitive((Long[]) array); + } + if(Short.TYPE.equals(pt)) { + return toPrimitive((Short[]) array); + } + if(Double.TYPE.equals(pt)) { + return toPrimitive((Double[]) array); + } + if(Float.TYPE.equals(pt)) { + return toPrimitive((Float[]) array); + } + return array; + } + + // Boolean array converters + // ---------------------------------------------------------------------- + /** + *

              Converts an array of object Booleans to primitives. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Boolean} array, may be {@code null} + * @return a {@code boolean} array, {@code null} if null array input + * @throws NullPointerException if array content is {@code null} + */ + public static boolean[] toPrimitive(final Boolean[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_BOOLEAN_ARRAY; + } + final boolean[] result = new boolean[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].booleanValue(); + } + return result; + } + + /** + *

              Converts an array of object Booleans to primitives handling {@code null}. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code Boolean} array, may be {@code null} + * @param valueForNull the value to insert if {@code null} found + * @return a {@code boolean} array, {@code null} if null array input + */ + public static boolean[] toPrimitive(final Boolean[] array, final boolean valueForNull) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_BOOLEAN_ARRAY; + } + final boolean[] result = new boolean[array.length]; + for (int i = 0; i < array.length; i++) { + final Boolean b = array[i]; + result[i] = (b == null ? valueForNull : b.booleanValue()); + } + return result; + } + + /** + *

              Converts an array of primitive booleans to objects. + * + *

              This method returns {@code null} for a {@code null} input array. + * + * @param array a {@code boolean} array + * @return a {@code Boolean} array, {@code null} if null array input + */ + public static Boolean[] toObject(final boolean[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_BOOLEAN_OBJECT_ARRAY; + } + final Boolean[] result = new Boolean[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (array[i] ? Boolean.TRUE : Boolean.FALSE); + } + return result; + } + + // ---------------------------------------------------------------------- + /** + *

              Checks if an array of Objects is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final Object[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive longs is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final long[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive ints is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final int[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive shorts is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final short[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive chars is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final char[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive bytes is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final byte[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive doubles is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final double[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive floats is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final float[] array) { + return getLength(array) == 0; + } + + /** + *

              Checks if an array of primitive booleans is empty or {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is empty or {@code null} + * @since 2.1 + */ + public static boolean isEmpty(final boolean[] array) { + return getLength(array) == 0; + } + + // ---------------------------------------------------------------------- + /** + *

              Checks if an array of Objects is not empty and not {@code null}. + * + * @param the component type of the array + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final T[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive longs is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final long[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive ints is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final int[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive shorts is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final short[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive chars is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final char[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive bytes is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final byte[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive doubles is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final double[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive floats is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final float[] array) { + return !isEmpty(array); + } + + /** + *

              Checks if an array of primitive booleans is not empty and not {@code null}. + * + * @param array the array to test + * @return {@code true} if the array is not empty and not {@code null} + * @since 2.5 + */ + public static boolean isNotEmpty(final boolean[] array) { + return !isEmpty(array); + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(null, null)     = null
              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * ArrayUtils.addAll([null], [null]) = [null, null]
              +     * ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
              +     * 
              + * + * @param the component type of the array + * @param array1 the first array whose elements are added to the new array, may be {@code null} + * @param array2 the second array whose elements are added to the new array, may be {@code null} + * @return The new array, {@code null} if both arrays are {@code null}. + * The type of the new array is the type of the first array, + * unless the first array is null, in which case the type is the same as the second array. + * @since 2.1 + * @throws IllegalArgumentException if the array types are incompatible + */ + @SafeVarargs + public static T[] addAll(final T[] array1, final T... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final Class type1 = array1.getClass().getComponentType(); + @SuppressWarnings("unchecked") // OK, because array is of type T + final T[] joinedArray = (T[]) Array.newInstance(type1, array1.length + array2.length); + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + try { + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + } catch (final ArrayStoreException ase) { + // Check if problem was due to incompatible types + /* + * We do this here, rather than before the copy because: + * - it would be a wasted check most of the time + * - safer, in case check turns out to be too strict + */ + final Class type2 = array2.getClass().getComponentType(); + if (!type1.isAssignableFrom(type2)) { + throw new IllegalArgumentException("Cannot store " + type2.getName() + " in an array of " + + type1.getName(), ase); + } + throw ase; // No, so rethrow original + } + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new boolean[] array. + * @since 2.1 + */ + public static boolean[] addAll(final boolean[] array1, final boolean... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final boolean[] joinedArray = new boolean[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new char[] array. + * @since 2.1 + */ + public static char[] addAll(final char[] array1, final char... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final char[] joinedArray = new char[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new byte[] array. + * @since 2.1 + */ + public static byte[] addAll(final byte[] array1, final byte... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final byte[] joinedArray = new byte[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new short[] array. + * @since 2.1 + */ + public static short[] addAll(final short[] array1, final short... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final short[] joinedArray = new short[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new int[] array. + * @since 2.1 + */ + public static int[] addAll(final int[] array1, final int... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final int[] joinedArray = new int[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new long[] array. + * @since 2.1 + */ + public static long[] addAll(final long[] array1, final long... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final long[] joinedArray = new long[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new float[] array. + * @since 2.1 + */ + public static float[] addAll(final float[] array1, final float... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final float[] joinedArray = new float[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Adds all the elements of the given arrays into a new array. + *

              The new array contains all of the element of {@code array1} followed + * by all of the elements {@code array2}. When an array is returned, it is always + * a new array. + * + *

              +     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
              +     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
              +     * ArrayUtils.addAll([], [])         = []
              +     * 
              + * + * @param array1 the first array whose elements are added to the new array. + * @param array2 the second array whose elements are added to the new array. + * @return The new double[] array. + * @since 2.1 + */ + public static double[] addAll(final double[] array1, final double... array2) { + if (array1 == null) { + return clone(array2); + } else if (array2 == null) { + return clone(array1); + } + final double[] joinedArray = new double[array1.length + array2.length]; + System.arraycopy(array1, 0, joinedArray, 0, array1.length); + System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); + return joinedArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element, unless the element itself is null, + * in which case the return type is Object[] + * + *

              +     * ArrayUtils.add(null, null)      = IllegalArgumentException
              +     * ArrayUtils.add(null, "a")       = ["a"]
              +     * ArrayUtils.add(["a"], null)     = ["a", null]
              +     * ArrayUtils.add(["a"], "b")      = ["a", "b"]
              +     * ArrayUtils.add(["a", "b"], "c") = ["a", "b", "c"]
              +     * 
              + * + * @param the component type of the array + * @param array the array to "add" the element to, may be {@code null} + * @param element the object to add, may be {@code null} + * @return A new array containing the existing elements plus the new element + * The returned array type will be that of the input array (unless null), + * in which case it will have the same type as the element. + * If both are null, an IllegalArgumentException is thrown + * @since 2.1 + * @throws IllegalArgumentException if both arguments are null + */ + public static T[] add(final T[] array, final T element) { + Class type; + if (array != null) { + type = array.getClass().getComponentType(); + } else if (element != null) { + type = element.getClass(); + } else { + throw new IllegalArgumentException("Arguments cannot both be null"); + } + @SuppressWarnings("unchecked") // type must be T + final + T[] newArray = (T[]) copyArrayGrow1(array, type); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, true)          = [true]
              +     * ArrayUtils.add([true], false)       = [true, false]
              +     * ArrayUtils.add([true, false], true) = [true, false, true]
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static boolean[] add(final boolean[] array, final boolean element) { + final boolean[] newArray = (boolean[])copyArrayGrow1(array, Boolean.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0)   = [0]
              +     * ArrayUtils.add([1], 0)    = [1, 0]
              +     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static byte[] add(final byte[] array, final byte element) { + final byte[] newArray = (byte[])copyArrayGrow1(array, Byte.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, '0')       = ['0']
              +     * ArrayUtils.add(['1'], '0')      = ['1', '0']
              +     * ArrayUtils.add(['1', '0'], '1') = ['1', '0', '1']
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static char[] add(final char[] array, final char element) { + final char[] newArray = (char[])copyArrayGrow1(array, Character.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0)   = [0]
              +     * ArrayUtils.add([1], 0)    = [1, 0]
              +     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static double[] add(final double[] array, final double element) { + final double[] newArray = (double[])copyArrayGrow1(array, Double.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0)   = [0]
              +     * ArrayUtils.add([1], 0)    = [1, 0]
              +     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static float[] add(final float[] array, final float element) { + final float[] newArray = (float[])copyArrayGrow1(array, Float.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0)   = [0]
              +     * ArrayUtils.add([1], 0)    = [1, 0]
              +     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static int[] add(final int[] array, final int element) { + final int[] newArray = (int[])copyArrayGrow1(array, Integer.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0)   = [0]
              +     * ArrayUtils.add([1], 0)    = [1, 0]
              +     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static long[] add(final long[] array, final long element) { + final long[] newArray = (long[])copyArrayGrow1(array, Long.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + *

              Copies the given array and adds the given element at the end of the new array. + * + *

              The new array contains the same elements of the input + * array plus the given element in the last position. The component type of + * the new array is the same as that of the input array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0)   = [0]
              +     * ArrayUtils.add([1], 0)    = [1, 0]
              +     * ArrayUtils.add([1, 0], 1) = [1, 0, 1]
              +     * 
              + * + * @param array the array to copy and add the element to, may be {@code null} + * @param element the object to add at the last index of the new array + * @return A new array containing the existing elements plus the new element + * @since 2.1 + */ + public static short[] add(final short[] array, final short element) { + final short[] newArray = (short[]) copyArrayGrow1(array, Short.TYPE); + newArray[newArray.length - 1] = element; + return newArray; + } + + /** + * Returns a copy of the given array of size 1 greater than the argument. + * The last value of the array is left to the default value. + * + * @param array The array to copy, must not be {@code null}. + * @param newArrayComponentType If {@code array} is {@code null}, create a + * size 1 array of this type. + * @return A new copy of the array of size 1 greater than the input. + */ + private static Object copyArrayGrow1(final Object array, final Class newArrayComponentType) { + if (array != null) { + final int arrayLength = Array.getLength(array); + final Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1); + System.arraycopy(array, 0, newArray, 0, arrayLength); + return newArray; + } + return Array.newInstance(newArrayComponentType, 1); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0, null)      = IllegalArgumentException
              +     * ArrayUtils.add(null, 0, "a")       = ["a"]
              +     * ArrayUtils.add(["a"], 1, null)     = ["a", null]
              +     * ArrayUtils.add(["a"], 1, "b")      = ["a", "b"]
              +     * ArrayUtils.add(["a", "b"], 3, "c") = ["a", "b", "c"]
              +     * 
              + * + * @param the component type of the array + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index > array.length). + * @throws IllegalArgumentException if both array and element are null + * @deprecated this method has been superseded by {@link #insert(int, Object[], Object...) insert(int, T[], T...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static T[] add(final T[] array, final int index, final T element) { + Class clss = null; + if (array != null) { + clss = array.getClass().getComponentType(); + } else if (element != null) { + clss = element.getClass(); + } else { + throw new IllegalArgumentException("Array and element cannot both be null"); + } + @SuppressWarnings("unchecked") // the add method creates an array of type clss, which is type T + final T[] newArray = (T[]) add(array, index, element, clss); + return newArray; + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0, true)          = [true]
              +     * ArrayUtils.add([true], 0, false)       = [false, true]
              +     * ArrayUtils.add([false], 1, true)       = [false, true]
              +     * ArrayUtils.add([true, false], 1, true) = [true, true, false]
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, boolean[], boolean...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static boolean[] add(final boolean[] array, final int index, final boolean element) { + return (boolean[]) add(array, index, Boolean.valueOf(element), Boolean.TYPE); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add(null, 0, 'a')            = ['a']
              +     * ArrayUtils.add(['a'], 0, 'b')           = ['b', 'a']
              +     * ArrayUtils.add(['a', 'b'], 0, 'c')      = ['c', 'a', 'b']
              +     * ArrayUtils.add(['a', 'b'], 1, 'k')      = ['a', 'k', 'b']
              +     * ArrayUtils.add(['a', 'b', 'c'], 1, 't') = ['a', 't', 'b', 'c']
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, char[], char...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static char[] add(final char[] array, final int index, final char element) { + return (char[]) add(array, index, Character.valueOf(element), Character.TYPE); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add([1], 0, 2)         = [2, 1]
              +     * ArrayUtils.add([2, 6], 2, 3)      = [2, 6, 3]
              +     * ArrayUtils.add([2, 6], 0, 1)      = [1, 2, 6]
              +     * ArrayUtils.add([2, 6, 3], 2, 1)   = [2, 6, 1, 3]
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, byte[], byte...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static byte[] add(final byte[] array, final int index, final byte element) { + return (byte[]) add(array, index, Byte.valueOf(element), Byte.TYPE); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add([1], 0, 2)         = [2, 1]
              +     * ArrayUtils.add([2, 6], 2, 10)     = [2, 6, 10]
              +     * ArrayUtils.add([2, 6], 0, -4)     = [-4, 2, 6]
              +     * ArrayUtils.add([2, 6, 3], 2, 1)   = [2, 6, 1, 3]
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, short[], short...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static short[] add(final short[] array, final int index, final short element) { + return (short[]) add(array, index, Short.valueOf(element), Short.TYPE); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add([1], 0, 2)         = [2, 1]
              +     * ArrayUtils.add([2, 6], 2, 10)     = [2, 6, 10]
              +     * ArrayUtils.add([2, 6], 0, -4)     = [-4, 2, 6]
              +     * ArrayUtils.add([2, 6, 3], 2, 1)   = [2, 6, 1, 3]
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, int[], int...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static int[] add(final int[] array, final int index, final int element) { + return (int[]) add(array, index, Integer.valueOf(element), Integer.TYPE); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add([1L], 0, 2L)           = [2L, 1L]
              +     * ArrayUtils.add([2L, 6L], 2, 10L)      = [2L, 6L, 10L]
              +     * ArrayUtils.add([2L, 6L], 0, -4L)      = [-4L, 2L, 6L]
              +     * ArrayUtils.add([2L, 6L, 3L], 2, 1L)   = [2L, 6L, 1L, 3L]
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, long[], long...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static long[] add(final long[] array, final int index, final long element) { + return (long[]) add(array, index, Long.valueOf(element), Long.TYPE); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add([1.1f], 0, 2.2f)               = [2.2f, 1.1f]
              +     * ArrayUtils.add([2.3f, 6.4f], 2, 10.5f)        = [2.3f, 6.4f, 10.5f]
              +     * ArrayUtils.add([2.6f, 6.7f], 0, -4.8f)        = [-4.8f, 2.6f, 6.7f]
              +     * ArrayUtils.add([2.9f, 6.0f, 0.3f], 2, 1.0f)   = [2.9f, 6.0f, 1.0f, 0.3f]
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, float[], float...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static float[] add(final float[] array, final int index, final float element) { + return (float[]) add(array, index, Float.valueOf(element), Float.TYPE); + } + + /** + *

              Inserts the specified element at the specified position in the array. + * Shifts the element currently at that position (if any) and any subsequent + * elements to the right (adds one to their indices). + * + *

              This method returns a new array with the same elements of the input + * array plus the given element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, a new one element array is returned + * whose component type is the same as the element. + * + *

              +     * ArrayUtils.add([1.1], 0, 2.2)              = [2.2, 1.1]
              +     * ArrayUtils.add([2.3, 6.4], 2, 10.5)        = [2.3, 6.4, 10.5]
              +     * ArrayUtils.add([2.6, 6.7], 0, -4.8)        = [-4.8, 2.6, 6.7]
              +     * ArrayUtils.add([2.9, 6.0, 0.3], 2, 1.0)    = [2.9, 6.0, 1.0, 0.3]
              +     * 
              + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @return A new array containing the existing elements and the new element + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index > array.length). + * @deprecated this method has been superseded by {@link #insert(int, double[], double...)} and + * may be removed in a future release. Please note the handling of {@code null} input arrays differs + * in the new method: inserting {@code X} into a {@code null} array results in {@code null} not {@code X}. + */ + @Deprecated + public static double[] add(final double[] array, final int index, final double element) { + return (double[]) add(array, index, Double.valueOf(element), Double.TYPE); + } + + /** + * Underlying implementation of add(array, index, element) methods. + * The last parameter is the class, which may not equal element.getClass + * for primitives. + * + * @param array the array to add the element to, may be {@code null} + * @param index the position of the new object + * @param element the object to add + * @param clss the type of the element being added + * @return A new array containing the existing elements and the new element + */ + private static Object add(final Object array, final int index, final Object element, final Class clss) { + if (array == null) { + if (index != 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: 0"); + } + final Object joinedArray = Array.newInstance(clss, 1); + Array.set(joinedArray, 0, element); + return joinedArray; + } + final int length = Array.getLength(array); + if (index > length || index < 0) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length); + } + final Object result = Array.newInstance(clss, length + 1); + System.arraycopy(array, 0, result, 0, index); + Array.set(result, index, element); + if (index < length) { + System.arraycopy(array, index, result, index + 1, length - index); + } + return result; + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove(["a"], 0)           = []
              +     * ArrayUtils.remove(["a", "b"], 0)      = ["b"]
              +     * ArrayUtils.remove(["a", "b"], 1)      = ["a"]
              +     * ArrayUtils.remove(["a", "b", "c"], 1) = ["a", "c"]
              +     * 
              + * + * @param the component type of the array + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + @SuppressWarnings("unchecked") // remove() always creates an array of the same type as its input + public static T[] remove(final T[] array, final int index) { + return (T[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, "a")            = null
              +     * ArrayUtils.removeElement([], "a")              = []
              +     * ArrayUtils.removeElement(["a"], "b")           = ["a"]
              +     * ArrayUtils.removeElement(["a", "b"], "a")      = ["b"]
              +     * ArrayUtils.removeElement(["a", "b", "a"], "a") = ["b", "a"]
              +     * 
              + * + * @param the component type of the array + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static T[] removeElement(final T[] array, final Object element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove([true], 0)              = []
              +     * ArrayUtils.remove([true, false], 0)       = [false]
              +     * ArrayUtils.remove([true, false], 1)       = [true]
              +     * ArrayUtils.remove([true, true, false], 1) = [true, false]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static boolean[] remove(final boolean[] array, final int index) { + return (boolean[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, true)                = null
              +     * ArrayUtils.removeElement([], true)                  = []
              +     * ArrayUtils.removeElement([true], false)             = [true]
              +     * ArrayUtils.removeElement([true, false], false)      = [true]
              +     * ArrayUtils.removeElement([true, false, true], true) = [false, true]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static boolean[] removeElement(final boolean[] array, final boolean element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove([1], 0)          = []
              +     * ArrayUtils.remove([1, 0], 0)       = [0]
              +     * ArrayUtils.remove([1, 0], 1)       = [1]
              +     * ArrayUtils.remove([1, 0, 1], 1)    = [1, 1]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static byte[] remove(final byte[] array, final int index) { + return (byte[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, 1)        = null
              +     * ArrayUtils.removeElement([], 1)          = []
              +     * ArrayUtils.removeElement([1], 0)         = [1]
              +     * ArrayUtils.removeElement([1, 0], 0)      = [1]
              +     * ArrayUtils.removeElement([1, 0, 1], 1)   = [0, 1]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static byte[] removeElement(final byte[] array, final byte element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove(['a'], 0)           = []
              +     * ArrayUtils.remove(['a', 'b'], 0)      = ['b']
              +     * ArrayUtils.remove(['a', 'b'], 1)      = ['a']
              +     * ArrayUtils.remove(['a', 'b', 'c'], 1) = ['a', 'c']
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static char[] remove(final char[] array, final int index) { + return (char[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, 'a')            = null
              +     * ArrayUtils.removeElement([], 'a')              = []
              +     * ArrayUtils.removeElement(['a'], 'b')           = ['a']
              +     * ArrayUtils.removeElement(['a', 'b'], 'a')      = ['b']
              +     * ArrayUtils.removeElement(['a', 'b', 'a'], 'a') = ['b', 'a']
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static char[] removeElement(final char[] array, final char element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove([1.1], 0)           = []
              +     * ArrayUtils.remove([2.5, 6.0], 0)      = [6.0]
              +     * ArrayUtils.remove([2.5, 6.0], 1)      = [2.5]
              +     * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static double[] remove(final double[] array, final int index) { + return (double[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, 1.1)            = null
              +     * ArrayUtils.removeElement([], 1.1)              = []
              +     * ArrayUtils.removeElement([1.1], 1.2)           = [1.1]
              +     * ArrayUtils.removeElement([1.1, 2.3], 1.1)      = [2.3]
              +     * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static double[] removeElement(final double[] array, final double element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove([1.1], 0)           = []
              +     * ArrayUtils.remove([2.5, 6.0], 0)      = [6.0]
              +     * ArrayUtils.remove([2.5, 6.0], 1)      = [2.5]
              +     * ArrayUtils.remove([2.5, 6.0, 3.8], 1) = [2.5, 3.8]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static float[] remove(final float[] array, final int index) { + return (float[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, 1.1)            = null
              +     * ArrayUtils.removeElement([], 1.1)              = []
              +     * ArrayUtils.removeElement([1.1], 1.2)           = [1.1]
              +     * ArrayUtils.removeElement([1.1, 2.3], 1.1)      = [2.3]
              +     * ArrayUtils.removeElement([1.1, 2.3, 1.1], 1.1) = [2.3, 1.1]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static float[] removeElement(final float[] array, final float element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove([1], 0)         = []
              +     * ArrayUtils.remove([2, 6], 0)      = [6]
              +     * ArrayUtils.remove([2, 6], 1)      = [2]
              +     * ArrayUtils.remove([2, 6, 3], 1)   = [2, 3]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static int[] remove(final int[] array, final int index) { + return (int[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, 1)      = null
              +     * ArrayUtils.removeElement([], 1)        = []
              +     * ArrayUtils.removeElement([1], 2)       = [1]
              +     * ArrayUtils.removeElement([1, 3], 1)    = [3]
              +     * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static int[] removeElement(final int[] array, final int element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove([1], 0)         = []
              +     * ArrayUtils.remove([2, 6], 0)      = [6]
              +     * ArrayUtils.remove([2, 6], 1)      = [2]
              +     * ArrayUtils.remove([2, 6, 3], 1)   = [2, 3]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static long[] remove(final long[] array, final int index) { + return (long[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, 1)      = null
              +     * ArrayUtils.removeElement([], 1)        = []
              +     * ArrayUtils.removeElement([1], 2)       = [1]
              +     * ArrayUtils.removeElement([1, 3], 1)    = [3]
              +     * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static long[] removeElement(final long[] array, final long element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.remove([1], 0)         = []
              +     * ArrayUtils.remove([2, 6], 0)      = [6]
              +     * ArrayUtils.remove([2, 6], 1)      = [2]
              +     * ArrayUtils.remove([2, 6, 3], 1)   = [2, 3]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + public static short[] remove(final short[] array, final int index) { + return (short[]) remove((Object) array, index); + } + + /** + *

              Removes the first occurrence of the specified element from the + * specified array. All subsequent elements are shifted to the left + * (subtracts one from their indices). If the array doesn't contains + * such an element, no elements are removed from the array. + * + *

              This method returns a new array with the same elements of the input + * array except the first occurrence of the specified element. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              +     * ArrayUtils.removeElement(null, 1)      = null
              +     * ArrayUtils.removeElement([], 1)        = []
              +     * ArrayUtils.removeElement([1], 2)       = [1]
              +     * ArrayUtils.removeElement([1, 3], 1)    = [3]
              +     * ArrayUtils.removeElement([1, 3, 1], 1) = [3, 1]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param element the element to be removed + * @return A new array containing the existing elements except the first + * occurrence of the specified element. + * @since 2.1 + */ + public static short[] removeElement(final short[] array, final short element) { + final int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + return remove(array, index); + } + + /** + *

              Removes the element at the specified position from the specified array. + * All subsequent elements are shifted to the left (subtracts one from + * their indices). + * + *

              This method returns a new array with the same elements of the input + * array except the element on the specified position. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + * @param array the array to remove the element from, may not be {@code null} + * @param index the position of the element to be removed + * @return A new array containing the existing elements except the element + * at the specified position. + * @throws IndexOutOfBoundsException if the index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 2.1 + */ + private static Object remove(final Object array, final int index) { + final int length = getLength(array); + if (index < 0 || index >= length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length); + } + + final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1); + System.arraycopy(array, 0, result, 0, index); + if (index < length - 1) { + System.arraycopy(array, index + 1, result, index, length - index - 1); + } + + return result; + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll(["a", "b", "c"], 0, 2) = ["b"]
              +     * ArrayUtils.removeAll(["a", "b", "c"], 1, 2) = ["a"]
              +     * 
              + * + * @param the component type of the array + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + @SuppressWarnings("unchecked") // removeAll() always creates an array of the same type as its input + public static T[] removeAll(final T[] array, final int... indices) { + return (T[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, "a", "b")            = null
              +     * ArrayUtils.removeElements([], "a", "b")              = []
              +     * ArrayUtils.removeElements(["a"], "b", "c")           = ["a"]
              +     * ArrayUtils.removeElements(["a", "b"], "a", "c")      = ["b"]
              +     * ArrayUtils.removeElements(["a", "b", "a"], "a")      = ["b", "a"]
              +     * ArrayUtils.removeElements(["a", "b", "a"], "a", "a") = ["b"]
              +     * 
              + * + * @param the component type of the array + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + @SafeVarargs + public static T[] removeElements(final T[] array, final T... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(values.length); + for (final T v : values) { + final MutableInt count = occurrences.get(v); + if (count == null) { + occurrences.put(v, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final T key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + @SuppressWarnings("unchecked") // removeAll() always creates an array of the same type as its input + final T[] result = (T[]) removeAll(array, toRemove); + return result; + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([1], 0)             = []
              +     * ArrayUtils.removeAll([2, 6], 0)          = [6]
              +     * ArrayUtils.removeAll([2, 6], 0, 1)       = []
              +     * ArrayUtils.removeAll([2, 6, 3], 1, 2)    = [2]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 2)    = [6]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static byte[] removeAll(final byte[] array, final int... indices) { + return (byte[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, 1, 2)      = null
              +     * ArrayUtils.removeElements([], 1, 2)        = []
              +     * ArrayUtils.removeElements([1], 2, 3)       = [1]
              +     * ArrayUtils.removeElements([1, 3], 1, 2)    = [3]
              +     * ArrayUtils.removeElements([1, 3, 1], 1)    = [3, 1]
              +     * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static byte[] removeElements(final byte[] array, final byte... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final Map occurrences = new HashMap<>(values.length); + for (final byte v : values) { + final Byte boxed = Byte.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final byte key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (byte[]) removeAll(array, toRemove); + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([1], 0)             = []
              +     * ArrayUtils.removeAll([2, 6], 0)          = [6]
              +     * ArrayUtils.removeAll([2, 6], 0, 1)       = []
              +     * ArrayUtils.removeAll([2, 6, 3], 1, 2)    = [2]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 2)    = [6]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static short[] removeAll(final short[] array, final int... indices) { + return (short[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, 1, 2)      = null
              +     * ArrayUtils.removeElements([], 1, 2)        = []
              +     * ArrayUtils.removeElements([1], 2, 3)       = [1]
              +     * ArrayUtils.removeElements([1, 3], 1, 2)    = [3]
              +     * ArrayUtils.removeElements([1, 3, 1], 1)    = [3, 1]
              +     * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static short[] removeElements(final short[] array, final short... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(values.length); + for (final short v : values) { + final Short boxed = Short.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final short key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (short[]) removeAll(array, toRemove); + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([1], 0)             = []
              +     * ArrayUtils.removeAll([2, 6], 0)          = [6]
              +     * ArrayUtils.removeAll([2, 6], 0, 1)       = []
              +     * ArrayUtils.removeAll([2, 6, 3], 1, 2)    = [2]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 2)    = [6]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static int[] removeAll(final int[] array, final int... indices) { + return (int[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, 1, 2)      = null
              +     * ArrayUtils.removeElements([], 1, 2)        = []
              +     * ArrayUtils.removeElements([1], 2, 3)       = [1]
              +     * ArrayUtils.removeElements([1, 3], 1, 2)    = [3]
              +     * ArrayUtils.removeElements([1, 3, 1], 1)    = [3, 1]
              +     * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static int[] removeElements(final int[] array, final int... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(values.length); + for (final int v : values) { + final Integer boxed = Integer.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final int key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (int[]) removeAll(array, toRemove); + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([1], 0)             = []
              +     * ArrayUtils.removeAll([2, 6], 0)          = [6]
              +     * ArrayUtils.removeAll([2, 6], 0, 1)       = []
              +     * ArrayUtils.removeAll([2, 6, 3], 1, 2)    = [2]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 2)    = [6]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static char[] removeAll(final char[] array, final int... indices) { + return (char[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, 1, 2)      = null
              +     * ArrayUtils.removeElements([], 1, 2)        = []
              +     * ArrayUtils.removeElements([1], 2, 3)       = [1]
              +     * ArrayUtils.removeElements([1, 3], 1, 2)    = [3]
              +     * ArrayUtils.removeElements([1, 3, 1], 1)    = [3, 1]
              +     * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static char[] removeElements(final char[] array, final char... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(values.length); + for (final char v : values) { + final Character boxed = Character.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final char key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (char[]) removeAll(array, toRemove); + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([1], 0)             = []
              +     * ArrayUtils.removeAll([2, 6], 0)          = [6]
              +     * ArrayUtils.removeAll([2, 6], 0, 1)       = []
              +     * ArrayUtils.removeAll([2, 6, 3], 1, 2)    = [2]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 2)    = [6]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static long[] removeAll(final long[] array, final int... indices) { + return (long[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, 1, 2)      = null
              +     * ArrayUtils.removeElements([], 1, 2)        = []
              +     * ArrayUtils.removeElements([1], 2, 3)       = [1]
              +     * ArrayUtils.removeElements([1, 3], 1, 2)    = [3]
              +     * ArrayUtils.removeElements([1, 3, 1], 1)    = [3, 1]
              +     * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static long[] removeElements(final long[] array, final long... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(values.length); + for (final long v : values) { + final Long boxed = Long.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final long key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (long[]) removeAll(array, toRemove); + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([1], 0)             = []
              +     * ArrayUtils.removeAll([2, 6], 0)          = [6]
              +     * ArrayUtils.removeAll([2, 6], 0, 1)       = []
              +     * ArrayUtils.removeAll([2, 6, 3], 1, 2)    = [2]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 2)    = [6]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static float[] removeAll(final float[] array, final int... indices) { + return (float[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, 1, 2)      = null
              +     * ArrayUtils.removeElements([], 1, 2)        = []
              +     * ArrayUtils.removeElements([1], 2, 3)       = [1]
              +     * ArrayUtils.removeElements([1, 3], 1, 2)    = [3]
              +     * ArrayUtils.removeElements([1, 3, 1], 1)    = [3, 1]
              +     * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static float[] removeElements(final float[] array, final float... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(values.length); + for (final float v : values) { + final Float boxed = Float.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final float key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (float[]) removeAll(array, toRemove); + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([1], 0)             = []
              +     * ArrayUtils.removeAll([2, 6], 0)          = [6]
              +     * ArrayUtils.removeAll([2, 6], 0, 1)       = []
              +     * ArrayUtils.removeAll([2, 6, 3], 1, 2)    = [2]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 2)    = [6]
              +     * ArrayUtils.removeAll([2, 6, 3], 0, 1, 2) = []
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static double[] removeAll(final double[] array, final int... indices) { + return (double[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, 1, 2)      = null
              +     * ArrayUtils.removeElements([], 1, 2)        = []
              +     * ArrayUtils.removeElements([1], 2, 3)       = [1]
              +     * ArrayUtils.removeElements([1, 3], 1, 2)    = [3]
              +     * ArrayUtils.removeElements([1, 3, 1], 1)    = [3, 1]
              +     * ArrayUtils.removeElements([1, 3, 1], 1, 1) = [3]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static double[] removeElements(final double[] array, final double... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(values.length); + for (final double v : values) { + final Double boxed = Double.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final double key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (double[]) removeAll(array, toRemove); + } + + /** + *

              Removes the elements at the specified positions from the specified array. + * All remaining elements are shifted to the left. + * + *

              This method returns a new array with the same elements of the input + * array except those at the specified positions. The component + * type of the returned array is always the same as that of the input + * array. + * + *

              If the input array is {@code null}, an IndexOutOfBoundsException + * will be thrown, because in that case no valid index can be specified. + * + *

              +     * ArrayUtils.removeAll([true, false, true], 0, 2) = [false]
              +     * ArrayUtils.removeAll([true, false, true], 1, 2) = [true]
              +     * 
              + * + * @param array the array to remove the element from, may not be {@code null} + * @param indices the positions of the elements to be removed + * @return A new array containing the existing elements except those + * at the specified positions. + * @throws IndexOutOfBoundsException if any index is out of range + * (index < 0 || index >= array.length), or if the array is {@code null}. + * @since 3.0.1 + */ + public static boolean[] removeAll(final boolean[] array, final int... indices) { + return (boolean[]) removeAll((Object) array, indices); + } + + /** + *

              Removes occurrences of specified elements, in specified quantities, + * from the specified array. All subsequent elements are shifted left. + * For any element-to-be-removed specified in greater quantities than + * contained in the original array, no change occurs beyond the + * removal of the existing matching items. + * + *

              This method returns a new array with the same elements of the input + * array except for the earliest-encountered occurrences of the specified + * elements. The component type of the returned array is always the same + * as that of the input array. + * + *

              +     * ArrayUtils.removeElements(null, true, false)               = null
              +     * ArrayUtils.removeElements([], true, false)                 = []
              +     * ArrayUtils.removeElements([true], false, false)            = [true]
              +     * ArrayUtils.removeElements([true, false], true, true)       = [false]
              +     * ArrayUtils.removeElements([true, false, true], true)       = [false, true]
              +     * ArrayUtils.removeElements([true, false, true], true, true) = [false]
              +     * 
              + * + * @param array the array to remove the element from, may be {@code null} + * @param values the elements to be removed + * @return A new array containing the existing elements except the + * earliest-encountered occurrences of the specified elements. + * @since 3.0.1 + */ + public static boolean[] removeElements(final boolean[] array, final boolean... values) { + if (isEmpty(array) || isEmpty(values)) { + return clone(array); + } + final HashMap occurrences = new HashMap<>(2); // only two possible values here + for (final boolean v : values) { + final Boolean boxed = Boolean.valueOf(v); + final MutableInt count = occurrences.get(boxed); + if (count == null) { + occurrences.put(boxed, new MutableInt(1)); + } else { + count.increment(); + } + } + final BitSet toRemove = new BitSet(); + for (int i = 0; i < array.length; i++) { + final boolean key = array[i]; + final MutableInt count = occurrences.get(key); + if (count != null) { + if (count.decrementAndGet() == 0) { + occurrences.remove(key); + } + toRemove.set(i); + } + } + return (boolean[]) removeAll(array, toRemove); + } + + /** + * Removes multiple array elements specified by index. + * @param array source + * @param indices to remove + * @return new array of same type minus elements specified by unique values of {@code indices} + * @since 3.0.1 + */ + // package protected for access by unit tests + static Object removeAll(final Object array, final int... indices) { + final int length = getLength(array); + int diff = 0; // number of distinct indexes, i.e. number of entries that will be removed + final int[] clonedIndices = clone(indices); + Arrays.sort(clonedIndices); + + // identify length of result array + if (isNotEmpty(clonedIndices)) { + int i = clonedIndices.length; + int prevIndex = length; + while (--i >= 0) { + final int index = clonedIndices[i]; + if (index < 0 || index >= length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length); + } + if (index >= prevIndex) { + continue; + } + diff++; + prevIndex = index; + } + } + + // create result array + final Object result = Array.newInstance(array.getClass().getComponentType(), length - diff); + if (diff < length) { + int end = length; // index just after last copy + int dest = length - diff; // number of entries so far not copied + for (int i = clonedIndices.length - 1; i >= 0; i--) { + final int index = clonedIndices[i]; + if (end - index > 1) { // same as (cp > 0) + final int cp = end - index - 1; + dest -= cp; + System.arraycopy(array, index + 1, result, dest, cp); + // Afer this copy, we still have room for dest items. + } + end = index; + } + if (end > 0) { + System.arraycopy(array, 0, result, 0, end); + } + } + return result; + } + + /** + * Removes multiple array elements specified by indices. + * + * @param array source + * @param indices to remove + * @return new array of same type minus elements specified by the set bits in {@code indices} + * @since 3.2 + */ + // package protected for access by unit tests + static Object removeAll(final Object array, final BitSet indices) { + final int srcLength = ArrayUtils.getLength(array); + // No need to check maxIndex here, because method only currently called from removeElements() + // which guarantee to generate on;y valid bit entries. +// final int maxIndex = indices.length(); +// if (maxIndex > srcLength) { +// throw new IndexOutOfBoundsException("Index: " + (maxIndex-1) + ", Length: " + srcLength); +// } + final int removals = indices.cardinality(); // true bits are items to remove + final Object result = Array.newInstance(array.getClass().getComponentType(), srcLength - removals); + int srcIndex = 0; + int destIndex = 0; + int count; + int set; + while ((set = indices.nextSetBit(srcIndex)) != -1) { + count = set - srcIndex; + if (count > 0) { + System.arraycopy(array, srcIndex, result, destIndex, count); + destIndex += count; + } + srcIndex = indices.nextClearBit(set); + } + count = srcLength - srcIndex; + if (count > 0) { + System.arraycopy(array, srcIndex, result, destIndex, count); + } + return result; + } + + /** + *

              This method checks whether the provided array is sorted according to the class's + * {@code compareTo} method. + * + * @param array the array to check + * @param the datatype of the array to check, it must implement {@code Comparable} + * @return whether the array is sorted + * @since 3.4 + */ + public static > boolean isSorted(final T[] array) { + return isSorted(array, new Comparator() { + @Override + public int compare(final T o1, final T o2) { + return o1.compareTo(o2); + } + }); + } + + + /** + *

              This method checks whether the provided array is sorted according to the provided {@code Comparator}. + * + * @param array the array to check + * @param comparator the {@code Comparator} to compare over + * @param the datatype of the array + * @return whether the array is sorted + * @since 3.4 + */ + public static boolean isSorted(final T[] array, final Comparator comparator) { + if (comparator == null) { + throw new IllegalArgumentException("Comparator should not be null."); + } + + if (array == null || array.length < 2) { + return true; + } + + T previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final T current = array[i]; + if (comparator.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering. + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final int[] array) { + if (array == null || array.length < 2) { + return true; + } + + int previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final int current = array[i]; + if (NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering. + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final long[] array) { + if (array == null || array.length < 2) { + return true; + } + + long previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final long current = array[i]; + if (NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering. + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final short[] array) { + if (array == null || array.length < 2) { + return true; + } + + short previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final short current = array[i]; + if (NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering. + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final double[] array) { + if (array == null || array.length < 2) { + return true; + } + + double previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final double current = array[i]; + if (Double.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering. + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final float[] array) { + if (array == null || array.length < 2) { + return true; + } + + float previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final float current = array[i]; + if (Float.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering. + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final byte[] array) { + if (array == null || array.length < 2) { + return true; + } + + byte previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final byte current = array[i]; + if (NumberUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering. + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final char[] array) { + if (array == null || array.length < 2) { + return true; + } + + char previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final char current = array[i]; + if (CharUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + *

              This method checks whether the provided array is sorted according to natural ordering + * ({@code false} before {@code true}). + * + * @param array the array to check + * @return whether the array is sorted according to natural ordering + * @since 3.4 + */ + public static boolean isSorted(final boolean[] array) { + if (array == null || array.length < 2) { + return true; + } + + boolean previous = array[0]; + final int n = array.length; + for (int i = 1; i < n; i++) { + final boolean current = array[i]; + if (BooleanUtils.compare(previous, current) > 0) { + return false; + } + + previous = current; + } + return true; + } + + /** + * Removes the occurrences of the specified element from the specified boolean array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static boolean[] removeAllOccurences(final boolean[] array, final boolean element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified char array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static char[] removeAllOccurences(final char[] array, final char element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified byte array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static byte[] removeAllOccurences(final byte[] array, final byte element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified short array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static short[] removeAllOccurences(final short[] array, final short element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified int array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static int[] removeAllOccurences(final int[] array, final int element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified long array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static long[] removeAllOccurences(final long[] array, final long element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified float array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static float[] removeAllOccurences(final float[] array, final float element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified double array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static double[] removeAllOccurences(final double[] array, final double element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + * Removes the occurrences of the specified element from the specified array. + * + *

              + * All subsequent elements are shifted to the left (subtracts one from their indices). + * If the array doesn't contains such an element, no elements are removed from the array. + * null will be returned if the input array is null. + *

              + * + * @param the type of object in the array + * @param element the element to remove + * @param array the input array + * + * @return A new array containing the existing elements except the occurrences of the specified element. + * @since 3.5 + */ + public static T[] removeAllOccurences(final T[] array, final T element) { + int index = indexOf(array, element); + if (index == INDEX_NOT_FOUND) { + return clone(array); + } + + final int[] indices = new int[array.length - index]; + indices[0] = index; + int count = 1; + + while ((index = indexOf(array, element, indices[count - 1] + 1)) != INDEX_NOT_FOUND) { + indices[count++] = index; + } + + return removeAll(array, Arrays.copyOf(indices, count)); + } + + /** + *

              Returns an array containing the string representation of each element in the argument array.

              + * + *

              This method returns {@code null} for a {@code null} input array.

              + * + * @param array the {@code Object[]} to be processed, may be null + * @return {@code String[]} of the same size as the source with its element's string representation, + * {@code null} if null array input + * @throws NullPointerException if array contains {@code null} + * @since 3.6 + */ + public static String[] toStringArray(final Object[] array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return EMPTY_STRING_ARRAY; + } + + final String[] result = new String[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = array[i].toString(); + } + + return result; + } + + /** + *

              Returns an array containing the string representation of each element in the argument + * array handling {@code null} elements.

              + * + *

              This method returns {@code null} for a {@code null} input array.

              + * + * @param array the Object[] to be processed, may be null + * @param valueForNullElements the value to insert if {@code null} is found + * @return a {@code String} array, {@code null} if null array input + * @since 3.6 + */ + public static String[] toStringArray(final Object[] array, final String valueForNullElements) { + if (null == array) { + return null; + } else if (array.length == 0) { + return EMPTY_STRING_ARRAY; + } + + final String[] result = new String[array.length]; + for (int i = 0; i < array.length; i++) { + final Object object = array[i]; + result[i] = (object == null ? valueForNullElements : object.toString()); + } + + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static boolean[] insert(final int index, final boolean[] array, final boolean... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + boolean[] result = new boolean[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static byte[] insert(final int index, final byte[] array, final byte... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + byte[] result = new byte[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static char[] insert(final int index, final char[] array, final char... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + char[] result = new char[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static double[] insert(final int index, final double[] array, final double... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + double[] result = new double[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static float[] insert(final int index, final float[] array, final float... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + float[] result = new float[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static int[] insert(final int index, final int[] array, final int... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + int[] result = new int[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static long[] insert(final int index, final long[] array, final long... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + long[] result = new long[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + public static short[] insert(final int index, final short[] array, final short... values) { + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + short[] result = new short[array.length + values.length]; + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } + + /** + *

              Inserts elements into an array at the given index (starting from zero).

              + * + *

              When an array is returned, it is always a new array.

              + * + *
              +     * ArrayUtils.insert(index, null, null)      = null
              +     * ArrayUtils.insert(index, array, null)     = cloned copy of 'array'
              +     * ArrayUtils.insert(index, null, values)    = null
              +     * 
              + * + * @param The type of elements in {@code array} and {@code values} + * @param index the position within {@code array} to insert the new values + * @param array the array to insert the values into, may be {@code null} + * @param values the new values to insert, may be {@code null} + * @return The new array. + * @throws IndexOutOfBoundsException if {@code array} is provided + * and either {@code index < 0} or {@code index > array.length} + * @since 3.6 + */ + @SafeVarargs + public static T[] insert(final int index, final T[] array, final T... values) { + /* + * Note on use of @SafeVarargs: + * + * By returning null when 'array' is null, we avoid returning the vararg + * array to the caller. We also avoid relying on the type of the vararg + * array, by inspecting the component type of 'array'. + */ + + if (array == null) { + return null; + } + if (values == null || values.length == 0) { + return clone(array); + } + if (index < 0 || index > array.length) { + throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length); + } + + final Class type = array.getClass().getComponentType(); + @SuppressWarnings("unchecked") // OK, because array and values are of type T + T[] result = (T[]) Array.newInstance(type, array.length + values.length); + + System.arraycopy(values, 0, result, index, values.length); + if (index > 0) { + System.arraycopy(array, 0, result, 0, index); + } + if (index < array.length) { + System.arraycopy(array, index, result, index + values.length, array.length - index); + } + return result; + } +} diff --git a/src/org/apache/commons/lang3/BitField.java b/src/org/apache/commons/lang3/BitField.java new file mode 100644 index 0000000..65b465e --- /dev/null +++ b/src/org/apache/commons/lang3/BitField.java @@ -0,0 +1,322 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +/** + *

              Supports operations on bit-mapped fields. Instances of this class can be + * used to store a flag or data within an {@code int}, {@code short} or + * {@code byte}.

              + * + *

              Each {@code BitField} is constructed with a mask value, which indicates + * the bits that will be used to store and retrieve the data for that field. + * For instance, the mask {@code 0xFF} indicates the least-significant byte + * should be used to store the data.

              + * + *

              As an example, consider a car painting machine that accepts + * paint instructions as integers. Bit fields can be used to encode this:

              + * + *
              + *    // blue, green and red are 1 byte values (0-255) stored in the three least 
              + *    // significant bytes
              + *    BitField blue = new BitField(0xFF);
              + *    BitField green = new BitField(0xFF00);
              + *    BitField red = new BitField(0xFF0000);
              + * 
              + *    // anyColor is a flag triggered if any color is used
              + *    BitField anyColor = new BitField(0xFFFFFF);
              + * 
              + *    // isMetallic is a single bit flag
              + *    BitField isMetallic = new BitField(0x1000000);
              + *
              + * + *

              Using these {@code BitField} instances, a paint instruction can be + * encoded into an integer:

              + * + *
              + *    int paintInstruction = 0;
              + *    paintInstruction = red.setValue(paintInstruction, 35);
              + *    paintInstruction = green.setValue(paintInstruction, 100);
              + *    paintInstruction = blue.setValue(paintInstruction, 255);
              + *
              + * + *

              Flags and data can be retrieved from the integer:

              + * + *
              + *    // Prints true if red, green or blue is non-zero
              + *    System.out.println(anyColor.isSet(paintInstruction));   // prints true
              + *   
              + *    // Prints value of red, green and blue
              + *    System.out.println(red.getValue(paintInstruction));     // prints 35
              + *    System.out.println(green.getValue(paintInstruction));   // prints 100
              + *    System.out.println(blue.getValue(paintInstruction));    // prints 255
              + *   
              + *    // Prints true if isMetallic was set 
              + *    System.out.println(isMetallic.isSet(paintInstruction)); // prints false
              + *
              + * + * @since 2.0 + */ +public class BitField { + + private final int _mask; + private final int _shift_count; + + /** + *

              Creates a BitField instance.

              + * + * @param mask the mask specifying which bits apply to this + * BitField. Bits that are set in this mask are the bits + * that this BitField operates on + */ + public BitField(final int mask) { + _mask = mask; + _shift_count = mask != 0 ? Integer.numberOfTrailingZeros(mask) : 0; + } + + /** + *

              Obtains the value for the specified BitField, appropriately + * shifted right.

              + * + *

              Many users of a BitField will want to treat the specified + * bits as an int value, and will not want to be aware that the + * value is stored as a BitField (and so shifted left so many + * bits).

              + * + * @see #setValue(int,int) + * @param holder the int data containing the bits we're interested + * in + * @return the selected bits, shifted right appropriately + */ + public int getValue(final int holder) { + return getRawValue(holder) >> _shift_count; + } + + /** + *

              Obtains the value for the specified BitField, appropriately + * shifted right, as a short.

              + * + *

              Many users of a BitField will want to treat the specified + * bits as an int value, and will not want to be aware that the + * value is stored as a BitField (and so shifted left so many + * bits).

              + * + * @see #setShortValue(short,short) + * @param holder the short data containing the bits we're + * interested in + * @return the selected bits, shifted right appropriately + */ + public short getShortValue(final short holder) { + return (short) getValue(holder); + } + + /** + *

              Obtains the value for the specified BitField, unshifted.

              + * + * @param holder the int data containing the bits we're + * interested in + * @return the selected bits + */ + public int getRawValue(final int holder) { + return holder & _mask; + } + + /** + *

              Obtains the value for the specified BitField, unshifted.

              + * + * @param holder the short data containing the bits we're + * interested in + * @return the selected bits + */ + public short getShortRawValue(final short holder) { + return (short) getRawValue(holder); + } + + /** + *

              Returns whether the field is set or not.

              + * + *

              This is most commonly used for a single-bit field, which is + * often used to represent a boolean value; the results of using + * it for a multi-bit field is to determine whether *any* of its + * bits are set.

              + * + * @param holder the int data containing the bits we're interested + * in + * @return {@code true} if any of the bits are set, + * else {@code false} + */ + public boolean isSet(final int holder) { + return (holder & _mask) != 0; + } + + /** + *

              Returns whether all of the bits are set or not.

              + * + *

              This is a stricter test than {@link #isSet(int)}, + * in that all of the bits in a multi-bit set must be set + * for this method to return {@code true}.

              + * + * @param holder the int data containing the bits we're + * interested in + * @return {@code true} if all of the bits are set, + * else {@code false} + */ + public boolean isAllSet(final int holder) { + return (holder & _mask) == _mask; + } + + /** + *

              Replaces the bits with new values.

              + * + * @see #getValue(int) + * @param holder the int data containing the bits we're + * interested in + * @param value the new value for the specified bits + * @return the value of holder with the bits from the value + * parameter replacing the old bits + */ + public int setValue(final int holder, final int value) { + return (holder & ~_mask) | ((value << _shift_count) & _mask); + } + + /** + *

              Replaces the bits with new values.

              + * + * @see #getShortValue(short) + * @param holder the short data containing the bits we're + * interested in + * @param value the new value for the specified bits + * @return the value of holder with the bits from the value + * parameter replacing the old bits + */ + public short setShortValue(final short holder, final short value) { + return (short) setValue(holder, value); + } + + /** + *

              Clears the bits.

              + * + * @param holder the int data containing the bits we're + * interested in + * @return the value of holder with the specified bits cleared + * (set to {@code 0}) + */ + public int clear(final int holder) { + return holder & ~_mask; + } + + /** + *

              Clears the bits.

              + * + * @param holder the short data containing the bits we're + * interested in + * @return the value of holder with the specified bits cleared + * (set to {@code 0}) + */ + public short clearShort(final short holder) { + return (short) clear(holder); + } + + /** + *

              Clears the bits.

              + * + * @param holder the byte data containing the bits we're + * interested in + * + * @return the value of holder with the specified bits cleared + * (set to {@code 0}) + */ + public byte clearByte(final byte holder) { + return (byte) clear(holder); + } + + /** + *

              Sets the bits.

              + * + * @param holder the int data containing the bits we're + * interested in + * @return the value of holder with the specified bits set + * to {@code 1} + */ + public int set(final int holder) { + return holder | _mask; + } + + /** + *

              Sets the bits.

              + * + * @param holder the short data containing the bits we're + * interested in + * @return the value of holder with the specified bits set + * to {@code 1} + */ + public short setShort(final short holder) { + return (short) set(holder); + } + + /** + *

              Sets the bits.

              + * + * @param holder the byte data containing the bits we're + * interested in + * + * @return the value of holder with the specified bits set + * to {@code 1} + */ + public byte setByte(final byte holder) { + return (byte) set(holder); + } + + /** + *

              Sets a boolean BitField.

              + * + * @param holder the int data containing the bits we're + * interested in + * @param flag indicating whether to set or clear the bits + * @return the value of holder with the specified bits set or + * cleared + */ + public int setBoolean(final int holder, final boolean flag) { + return flag ? set(holder) : clear(holder); + } + + /** + *

              Sets a boolean BitField.

              + * + * @param holder the short data containing the bits we're + * interested in + * @param flag indicating whether to set or clear the bits + * @return the value of holder with the specified bits set or + * cleared + */ + public short setShortBoolean(final short holder, final boolean flag) { + return flag ? setShort(holder) : clearShort(holder); + } + + /** + *

              Sets a boolean BitField.

              + * + * @param holder the byte data containing the bits we're + * interested in + * @param flag indicating whether to set or clear the bits + * @return the value of holder with the specified bits set or + * cleared + */ + public byte setByteBoolean(final byte holder, final boolean flag) { + return flag ? setByte(holder) : clearByte(holder); + } + +} diff --git a/src/org/apache/commons/lang3/BooleanUtils.java b/src/org/apache/commons/lang3/BooleanUtils.java new file mode 100644 index 0000000..9a21289 --- /dev/null +++ b/src/org/apache/commons/lang3/BooleanUtils.java @@ -0,0 +1,1101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import org.apache.commons.lang3.math.NumberUtils; + +/** + *

              Operations on boolean primitives and Boolean objects.

              + * + *

              This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

              + * + *

              #ThreadSafe#

              + * @since 2.0 + */ +public class BooleanUtils { + + /** + *

              {@code BooleanUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code BooleanUtils.negate(true);}.

              + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate.

              + */ + public BooleanUtils() { + super(); + } + + // Boolean utilities + //-------------------------------------------------------------------------- + /** + *

              Negates the specified boolean.

              + * + *

              If {@code null} is passed in, {@code null} will be returned.

              + * + *

              NOTE: This returns null and will throw a NullPointerException if unboxed to a boolean.

              + * + *
              +     *   BooleanUtils.negate(Boolean.TRUE)  = Boolean.FALSE;
              +     *   BooleanUtils.negate(Boolean.FALSE) = Boolean.TRUE;
              +     *   BooleanUtils.negate(null)          = null;
              +     * 
              + * + * @param bool the Boolean to negate, may be null + * @return the negated Boolean, or {@code null} if {@code null} input + */ + public static Boolean negate(final Boolean bool) { + if (bool == null) { + return null; + } + return bool.booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + // boolean Boolean methods + //----------------------------------------------------------------------- + /** + *

              Checks if a {@code Boolean} value is {@code true}, + * handling {@code null} by returning {@code false}.

              + * + *
              +     *   BooleanUtils.isTrue(Boolean.TRUE)  = true
              +     *   BooleanUtils.isTrue(Boolean.FALSE) = false
              +     *   BooleanUtils.isTrue(null)          = false
              +     * 
              + * + * @param bool the boolean to check, null returns {@code false} + * @return {@code true} only if the input is non-null and true + * @since 2.1 + */ + public static boolean isTrue(final Boolean bool) { + return Boolean.TRUE.equals(bool); + } + + /** + *

              Checks if a {@code Boolean} value is not {@code true}, + * handling {@code null} by returning {@code true}.

              + * + *
              +     *   BooleanUtils.isNotTrue(Boolean.TRUE)  = false
              +     *   BooleanUtils.isNotTrue(Boolean.FALSE) = true
              +     *   BooleanUtils.isNotTrue(null)          = true
              +     * 
              + * + * @param bool the boolean to check, null returns {@code true} + * @return {@code true} if the input is null or false + * @since 2.3 + */ + public static boolean isNotTrue(final Boolean bool) { + return !isTrue(bool); + } + + /** + *

              Checks if a {@code Boolean} value is {@code false}, + * handling {@code null} by returning {@code false}.

              + * + *
              +     *   BooleanUtils.isFalse(Boolean.TRUE)  = false
              +     *   BooleanUtils.isFalse(Boolean.FALSE) = true
              +     *   BooleanUtils.isFalse(null)          = false
              +     * 
              + * + * @param bool the boolean to check, null returns {@code false} + * @return {@code true} only if the input is non-null and false + * @since 2.1 + */ + public static boolean isFalse(final Boolean bool) { + return Boolean.FALSE.equals(bool); + } + + /** + *

              Checks if a {@code Boolean} value is not {@code false}, + * handling {@code null} by returning {@code true}.

              + * + *
              +     *   BooleanUtils.isNotFalse(Boolean.TRUE)  = true
              +     *   BooleanUtils.isNotFalse(Boolean.FALSE) = false
              +     *   BooleanUtils.isNotFalse(null)          = true
              +     * 
              + * + * @param bool the boolean to check, null returns {@code true} + * @return {@code true} if the input is null or true + * @since 2.3 + */ + public static boolean isNotFalse(final Boolean bool) { + return !isFalse(bool); + } + + //----------------------------------------------------------------------- + /** + *

              Converts a Boolean to a boolean handling {@code null} + * by returning {@code false}.

              + * + *
              +     *   BooleanUtils.toBoolean(Boolean.TRUE)  = true
              +     *   BooleanUtils.toBoolean(Boolean.FALSE) = false
              +     *   BooleanUtils.toBoolean(null)          = false
              +     * 
              + * + * @param bool the boolean to convert + * @return {@code true} or {@code false}, {@code null} returns {@code false} + */ + public static boolean toBoolean(final Boolean bool) { + return bool != null && bool.booleanValue(); + } + + /** + *

              Converts a Boolean to a boolean handling {@code null}.

              + * + *
              +     *   BooleanUtils.toBooleanDefaultIfNull(Boolean.TRUE, false) = true
              +     *   BooleanUtils.toBooleanDefaultIfNull(Boolean.FALSE, true) = false
              +     *   BooleanUtils.toBooleanDefaultIfNull(null, true)          = true
              +     * 
              + * + * @param bool the boolean to convert + * @param valueIfNull the boolean value to return if {@code null} + * @return {@code true} or {@code false} + */ + public static boolean toBooleanDefaultIfNull(final Boolean bool, final boolean valueIfNull) { + if (bool == null) { + return valueIfNull; + } + return bool.booleanValue(); + } + + // Integer to Boolean methods + //----------------------------------------------------------------------- + /** + *

              Converts an int to a boolean using the convention that {@code zero} + * is {@code false}.

              + * + *
              +     *   BooleanUtils.toBoolean(0) = false
              +     *   BooleanUtils.toBoolean(1) = true
              +     *   BooleanUtils.toBoolean(2) = true
              +     * 
              + * + * @param value the int to convert + * @return {@code true} if non-zero, {@code false} + * if zero + */ + public static boolean toBoolean(final int value) { + return value != 0; + } + + /** + *

              Converts an int to a Boolean using the convention that {@code zero} + * is {@code false}.

              + * + *
              +     *   BooleanUtils.toBoolean(0) = Boolean.FALSE
              +     *   BooleanUtils.toBoolean(1) = Boolean.TRUE
              +     *   BooleanUtils.toBoolean(2) = Boolean.TRUE
              +     * 
              + * + * @param value the int to convert + * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero, + * {@code null} if {@code null} + */ + public static Boolean toBooleanObject(final int value) { + return value == 0 ? Boolean.FALSE : Boolean.TRUE; + } + + /** + *

              Converts an Integer to a Boolean using the convention that {@code zero} + * is {@code false}.

              + * + *

              {@code null} will be converted to {@code null}.

              + * + *

              NOTE: This returns null and will throw a NullPointerException if unboxed to a boolean.

              + * + *
              +     *   BooleanUtils.toBoolean(Integer.valueOf(0))    = Boolean.FALSE
              +     *   BooleanUtils.toBoolean(Integer.valueOf(1))    = Boolean.TRUE
              +     *   BooleanUtils.toBoolean(Integer.valueOf(null)) = null
              +     * 
              + * + * @param value the Integer to convert + * @return Boolean.TRUE if non-zero, Boolean.FALSE if zero, + * {@code null} if {@code null} input + */ + public static Boolean toBooleanObject(final Integer value) { + if (value == null) { + return null; + } + return value.intValue() == 0 ? Boolean.FALSE : Boolean.TRUE; + } + + /** + *

              Converts an int to a boolean specifying the conversion values.

              + * + *
              +     *   BooleanUtils.toBoolean(0, 1, 0) = false
              +     *   BooleanUtils.toBoolean(1, 1, 0) = true
              +     *   BooleanUtils.toBoolean(2, 1, 2) = false
              +     *   BooleanUtils.toBoolean(2, 2, 0) = true
              +     * 
              + * + * @param value the Integer to convert + * @param trueValue the value to match for {@code true} + * @param falseValue the value to match for {@code false} + * @return {@code true} or {@code false} + * @throws IllegalArgumentException if no match + */ + public static boolean toBoolean(final int value, final int trueValue, final int falseValue) { + if (value == trueValue) { + return true; + } + if (value == falseValue) { + return false; + } + // no match + throw new IllegalArgumentException("The Integer did not match either specified value"); + } + + /** + *

              Converts an Integer to a boolean specifying the conversion values.

              + * + *
              +     *   BooleanUtils.toBoolean(Integer.valueOf(0), Integer.valueOf(1), Integer.valueOf(0)) = false
              +     *   BooleanUtils.toBoolean(Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(0)) = true
              +     *   BooleanUtils.toBoolean(Integer.valueOf(2), Integer.valueOf(1), Integer.valueOf(2)) = false
              +     *   BooleanUtils.toBoolean(Integer.valueOf(2), Integer.valueOf(2), Integer.valueOf(0)) = true
              +     *   BooleanUtils.toBoolean(null, null, Integer.valueOf(0))                     = true
              +     * 
              + * + * @param value the Integer to convert + * @param trueValue the value to match for {@code true}, may be {@code null} + * @param falseValue the value to match for {@code false}, may be {@code null} + * @return {@code true} or {@code false} + * @throws IllegalArgumentException if no match + */ + public static boolean toBoolean(final Integer value, final Integer trueValue, final Integer falseValue) { + if (value == null) { + if (trueValue == null) { + return true; + } + if (falseValue == null) { + return false; + } + } else if (value.equals(trueValue)) { + return true; + } else if (value.equals(falseValue)) { + return false; + } + // no match + throw new IllegalArgumentException("The Integer did not match either specified value"); + } + + /** + *

              Converts an int to a Boolean specifying the conversion values.

              + * + *

              NOTE: This returns null and will throw a NullPointerException if unboxed to a boolean.

              + * + *
              +     *   BooleanUtils.toBooleanObject(0, 0, 2, 3) = Boolean.TRUE
              +     *   BooleanUtils.toBooleanObject(2, 1, 2, 3) = Boolean.FALSE
              +     *   BooleanUtils.toBooleanObject(3, 1, 2, 3) = null
              +     * 
              + * + * @param value the Integer to convert + * @param trueValue the value to match for {@code true} + * @param falseValue the value to match for {@code false} + * @param nullValue the value to to match for {@code null} + * @return Boolean.TRUE, Boolean.FALSE, or {@code null} + * @throws IllegalArgumentException if no match + */ + public static Boolean toBooleanObject(final int value, final int trueValue, final int falseValue, final int nullValue) { + if (value == trueValue) { + return Boolean.TRUE; + } + if (value == falseValue) { + return Boolean.FALSE; + } + if (value == nullValue) { + return null; + } + // no match + throw new IllegalArgumentException("The Integer did not match any specified value"); + } + + /** + *

              Converts an Integer to a Boolean specifying the conversion values.

              + * + *

              NOTE: This returns null and will throw a NullPointerException if unboxed to a boolean.

              + * + *
              +     *   BooleanUtils.toBooleanObject(Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(2), Integer.valueOf(3)) = Boolean.TRUE
              +     *   BooleanUtils.toBooleanObject(Integer.valueOf(2), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)) = Boolean.FALSE
              +     *   BooleanUtils.toBooleanObject(Integer.valueOf(3), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)) = null
              +     * 
              + * + * @param value the Integer to convert + * @param trueValue the value to match for {@code true}, may be {@code null} + * @param falseValue the value to match for {@code false}, may be {@code null} + * @param nullValue the value to to match for {@code null}, may be {@code null} + * @return Boolean.TRUE, Boolean.FALSE, or {@code null} + * @throws IllegalArgumentException if no match + */ + public static Boolean toBooleanObject(final Integer value, final Integer trueValue, final Integer falseValue, final Integer nullValue) { + if (value == null) { + if (trueValue == null) { + return Boolean.TRUE; + } + if (falseValue == null) { + return Boolean.FALSE; + } + if (nullValue == null) { + return null; + } + } else if (value.equals(trueValue)) { + return Boolean.TRUE; + } else if (value.equals(falseValue)) { + return Boolean.FALSE; + } else if (value.equals(nullValue)) { + return null; + } + // no match + throw new IllegalArgumentException("The Integer did not match any specified value"); + } + + // Boolean to Integer methods + //----------------------------------------------------------------------- + /** + *

              Converts a boolean to an int using the convention that + * {@code zero} is {@code false}.

              + * + *
              +     *   BooleanUtils.toInteger(true)  = 1
              +     *   BooleanUtils.toInteger(false) = 0
              +     * 
              + * + * @param bool the boolean to convert + * @return one if {@code true}, zero if {@code false} + */ + public static int toInteger(final boolean bool) { + return bool ? 1 : 0; + } + + /** + *

              Converts a boolean to an Integer using the convention that + * {@code zero} is {@code false}.

              + * + *
              +     *   BooleanUtils.toIntegerObject(true)  = Integer.valueOf(1)
              +     *   BooleanUtils.toIntegerObject(false) = Integer.valueOf(0)
              +     * 
              + * + * @param bool the boolean to convert + * @return one if {@code true}, zero if {@code false} + */ + public static Integer toIntegerObject(final boolean bool) { + return bool ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO; + } + + /** + *

              Converts a Boolean to a Integer using the convention that + * {@code zero} is {@code false}.

              + * + *

              {@code null} will be converted to {@code null}.

              + * + *
              +     *   BooleanUtils.toIntegerObject(Boolean.TRUE)  = Integer.valueOf(1)
              +     *   BooleanUtils.toIntegerObject(Boolean.FALSE) = Integer.valueOf(0)
              +     * 
              + * + * @param bool the Boolean to convert + * @return one if Boolean.TRUE, zero if Boolean.FALSE, {@code null} if {@code null} + */ + public static Integer toIntegerObject(final Boolean bool) { + if (bool == null) { + return null; + } + return bool.booleanValue() ? NumberUtils.INTEGER_ONE : NumberUtils.INTEGER_ZERO; + } + + /** + *

              Converts a boolean to an int specifying the conversion values.

              + * + *
              +     *   BooleanUtils.toInteger(true, 1, 0)  = 1
              +     *   BooleanUtils.toInteger(false, 1, 0) = 0
              +     * 
              + * + * @param bool the to convert + * @param trueValue the value to return if {@code true} + * @param falseValue the value to return if {@code false} + * @return the appropriate value + */ + public static int toInteger(final boolean bool, final int trueValue, final int falseValue) { + return bool ? trueValue : falseValue; + } + + /** + *

              Converts a Boolean to an int specifying the conversion values.

              + * + *
              +     *   BooleanUtils.toInteger(Boolean.TRUE, 1, 0, 2)  = 1
              +     *   BooleanUtils.toInteger(Boolean.FALSE, 1, 0, 2) = 0
              +     *   BooleanUtils.toInteger(null, 1, 0, 2)          = 2
              +     * 
              + * + * @param bool the Boolean to convert + * @param trueValue the value to return if {@code true} + * @param falseValue the value to return if {@code false} + * @param nullValue the value to return if {@code null} + * @return the appropriate value + */ + public static int toInteger(final Boolean bool, final int trueValue, final int falseValue, final int nullValue) { + if (bool == null) { + return nullValue; + } + return bool.booleanValue() ? trueValue : falseValue; + } + + /** + *

              Converts a boolean to an Integer specifying the conversion values.

              + * + *
              +     *   BooleanUtils.toIntegerObject(true, Integer.valueOf(1), Integer.valueOf(0))  = Integer.valueOf(1)
              +     *   BooleanUtils.toIntegerObject(false, Integer.valueOf(1), Integer.valueOf(0)) = Integer.valueOf(0)
              +     * 
              + * + * @param bool the to convert + * @param trueValue the value to return if {@code true}, may be {@code null} + * @param falseValue the value to return if {@code false}, may be {@code null} + * @return the appropriate value + */ + public static Integer toIntegerObject(final boolean bool, final Integer trueValue, final Integer falseValue) { + return bool ? trueValue : falseValue; + } + + /** + *

              Converts a Boolean to an Integer specifying the conversion values.

              + * + *
              +     *   BooleanUtils.toIntegerObject(Boolean.TRUE, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2))  = Integer.valueOf(1)
              +     *   BooleanUtils.toIntegerObject(Boolean.FALSE, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2)) = Integer.valueOf(0)
              +     *   BooleanUtils.toIntegerObject(null, Integer.valueOf(1), Integer.valueOf(0), Integer.valueOf(2))          = Integer.valueOf(2)
              +     * 
              + * + * @param bool the Boolean to convert + * @param trueValue the value to return if {@code true}, may be {@code null} + * @param falseValue the value to return if {@code false}, may be {@code null} + * @param nullValue the value to return if {@code null}, may be {@code null} + * @return the appropriate value + */ + public static Integer toIntegerObject(final Boolean bool, final Integer trueValue, final Integer falseValue, final Integer nullValue) { + if (bool == null) { + return nullValue; + } + return bool.booleanValue() ? trueValue : falseValue; + } + + // String to Boolean methods + //----------------------------------------------------------------------- + /** + *

              Converts a String to a Boolean.

              + * + *

              {@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'} or {@code 'yes'} + * (case insensitive) will return {@code true}. + * {@code 'false'}, {@code 'off'}, {@code 'n'}, {@code 'f'} or {@code 'no'} + * (case insensitive) will return {@code false}. + * Otherwise, {@code null} is returned.

              + * + *

              NOTE: This returns null and will throw a NullPointerException if unboxed to a boolean.

              + * + *
              +     *   // N.B. case is not significant
              +     *   BooleanUtils.toBooleanObject(null)    = null
              +     *   BooleanUtils.toBooleanObject("true")  = Boolean.TRUE
              +     *   BooleanUtils.toBooleanObject("T")     = Boolean.TRUE // i.e. T[RUE]
              +     *   BooleanUtils.toBooleanObject("false") = Boolean.FALSE
              +     *   BooleanUtils.toBooleanObject("f")     = Boolean.FALSE // i.e. f[alse]
              +     *   BooleanUtils.toBooleanObject("No")    = Boolean.FALSE
              +     *   BooleanUtils.toBooleanObject("n")     = Boolean.FALSE // i.e. n[o]
              +     *   BooleanUtils.toBooleanObject("on")    = Boolean.TRUE
              +     *   BooleanUtils.toBooleanObject("ON")    = Boolean.TRUE
              +     *   BooleanUtils.toBooleanObject("off")   = Boolean.FALSE
              +     *   BooleanUtils.toBooleanObject("oFf")   = Boolean.FALSE
              +     *   BooleanUtils.toBooleanObject("yes")   = Boolean.TRUE
              +     *   BooleanUtils.toBooleanObject("Y")     = Boolean.TRUE // i.e. Y[ES]
              +     *   BooleanUtils.toBooleanObject("blue")  = null
              +     *   BooleanUtils.toBooleanObject("true ") = null // trailing space (too long)
              +     *   BooleanUtils.toBooleanObject("ono")   = null // does not match on or no
              +     * 
              + * + * @param str the String to check; upper and lower case are treated as the same + * @return the Boolean value of the string, {@code null} if no match or {@code null} input + */ + public static Boolean toBooleanObject(final String str) { + // Previously used equalsIgnoreCase, which was fast for interned 'true'. + // Non interned 'true' matched 15 times slower. + // + // Optimisation provides same performance as before for interned 'true'. + // Similar performance for null, 'false', and other strings not length 2/3/4. + // 'true'/'TRUE' match 4 times slower, 'tRUE'/'True' 7 times slower. + if (str == "true") { + return Boolean.TRUE; + } + if (str == null) { + return null; + } + switch (str.length()) { + case 1: { + final char ch0 = str.charAt(0); + if (ch0 == 'y' || ch0 == 'Y' || + ch0 == 't' || ch0 == 'T') { + return Boolean.TRUE; + } + if (ch0 == 'n' || ch0 == 'N' || + ch0 == 'f' || ch0 == 'F') { + return Boolean.FALSE; + } + break; + } + case 2: { + final char ch0 = str.charAt(0); + final char ch1 = str.charAt(1); + if ((ch0 == 'o' || ch0 == 'O') && + (ch1 == 'n' || ch1 == 'N') ) { + return Boolean.TRUE; + } + if ((ch0 == 'n' || ch0 == 'N') && + (ch1 == 'o' || ch1 == 'O') ) { + return Boolean.FALSE; + } + break; + } + case 3: { + final char ch0 = str.charAt(0); + final char ch1 = str.charAt(1); + final char ch2 = str.charAt(2); + if ((ch0 == 'y' || ch0 == 'Y') && + (ch1 == 'e' || ch1 == 'E') && + (ch2 == 's' || ch2 == 'S') ) { + return Boolean.TRUE; + } + if ((ch0 == 'o' || ch0 == 'O') && + (ch1 == 'f' || ch1 == 'F') && + (ch2 == 'f' || ch2 == 'F') ) { + return Boolean.FALSE; + } + break; + } + case 4: { + final char ch0 = str.charAt(0); + final char ch1 = str.charAt(1); + final char ch2 = str.charAt(2); + final char ch3 = str.charAt(3); + if ((ch0 == 't' || ch0 == 'T') && + (ch1 == 'r' || ch1 == 'R') && + (ch2 == 'u' || ch2 == 'U') && + (ch3 == 'e' || ch3 == 'E') ) { + return Boolean.TRUE; + } + break; + } + case 5: { + final char ch0 = str.charAt(0); + final char ch1 = str.charAt(1); + final char ch2 = str.charAt(2); + final char ch3 = str.charAt(3); + final char ch4 = str.charAt(4); + if ((ch0 == 'f' || ch0 == 'F') && + (ch1 == 'a' || ch1 == 'A') && + (ch2 == 'l' || ch2 == 'L') && + (ch3 == 's' || ch3 == 'S') && + (ch4 == 'e' || ch4 == 'E') ) { + return Boolean.FALSE; + } + break; + } + default: + break; + } + + return null; + } + + /** + *

              Converts a String to a Boolean throwing an exception if no match.

              + * + *

              NOTE: This returns null and will throw a NullPointerException if unboxed to a boolean.

              + * + *
              +     *   BooleanUtils.toBooleanObject("true", "true", "false", "null")  = Boolean.TRUE
              +     *   BooleanUtils.toBooleanObject("false", "true", "false", "null") = Boolean.FALSE
              +     *   BooleanUtils.toBooleanObject("null", "true", "false", "null")  = null
              +     * 
              + * + * @param str the String to check + * @param trueString the String to match for {@code true} (case sensitive), may be {@code null} + * @param falseString the String to match for {@code false} (case sensitive), may be {@code null} + * @param nullString the String to match for {@code null} (case sensitive), may be {@code null} + * @return the Boolean value of the string, {@code null} if either the String matches {@code nullString} + * or if {@code null} input and {@code nullString} is {@code null} + * @throws IllegalArgumentException if the String doesn't match + */ + public static Boolean toBooleanObject(final String str, final String trueString, final String falseString, final String nullString) { + if (str == null) { + if (trueString == null) { + return Boolean.TRUE; + } + if (falseString == null) { + return Boolean.FALSE; + } + if (nullString == null) { + return null; + } + } else if (str.equals(trueString)) { + return Boolean.TRUE; + } else if (str.equals(falseString)) { + return Boolean.FALSE; + } else if (str.equals(nullString)) { + return null; + } + // no match + throw new IllegalArgumentException("The String did not match any specified value"); + } + + // String to boolean methods + //----------------------------------------------------------------------- + /** + *

              Converts a String to a boolean (optimised for performance).

              + * + *

              {@code 'true'}, {@code 'on'}, {@code 'y'}, {@code 't'} or {@code 'yes'} + * (case insensitive) will return {@code true}. Otherwise, + * {@code false} is returned.

              + * + *

              This method performs 4 times faster (JDK1.4) than + * {@code Boolean.valueOf(String)}. However, this method accepts + * 'on' and 'yes', 't', 'y' as true values. + * + *

              +     *   BooleanUtils.toBoolean(null)    = false
              +     *   BooleanUtils.toBoolean("true")  = true
              +     *   BooleanUtils.toBoolean("TRUE")  = true
              +     *   BooleanUtils.toBoolean("tRUe")  = true
              +     *   BooleanUtils.toBoolean("on")    = true
              +     *   BooleanUtils.toBoolean("yes")   = true
              +     *   BooleanUtils.toBoolean("false") = false
              +     *   BooleanUtils.toBoolean("x gti") = false
              +     *   BooleanUtils.toBooleanObject("y") = true
              +     *   BooleanUtils.toBooleanObject("n") = false
              +     *   BooleanUtils.toBooleanObject("t") = true
              +     *   BooleanUtils.toBooleanObject("f") = false 
              +     * 
              + * + * @param str the String to check + * @return the boolean value of the string, {@code false} if no match or the String is null + */ + public static boolean toBoolean(final String str) { + return toBooleanObject(str) == Boolean.TRUE; + } + + /** + *

              Converts a String to a Boolean throwing an exception if no match found.

              + * + *
              +     *   BooleanUtils.toBoolean("true", "true", "false")  = true
              +     *   BooleanUtils.toBoolean("false", "true", "false") = false
              +     * 
              + * + * @param str the String to check + * @param trueString the String to match for {@code true} (case sensitive), may be {@code null} + * @param falseString the String to match for {@code false} (case sensitive), may be {@code null} + * @return the boolean value of the string + * @throws IllegalArgumentException if the String doesn't match + */ + public static boolean toBoolean(final String str, final String trueString, final String falseString) { + if (str == trueString) { + return true; + } else if (str == falseString) { + return false; + } else if (str != null) { + if (str.equals(trueString)) { + return true; + } else if (str.equals(falseString)) { + return false; + } + } + // no match + throw new IllegalArgumentException("The String did not match either specified value"); + } + + // Boolean to String methods + //----------------------------------------------------------------------- + /** + *

              Converts a Boolean to a String returning {@code 'true'}, + * {@code 'false'}, or {@code null}.

              + * + *
              +     *   BooleanUtils.toStringTrueFalse(Boolean.TRUE)  = "true"
              +     *   BooleanUtils.toStringTrueFalse(Boolean.FALSE) = "false"
              +     *   BooleanUtils.toStringTrueFalse(null)          = null;
              +     * 
              + * + * @param bool the Boolean to check + * @return {@code 'true'}, {@code 'false'}, or {@code null} + */ + public static String toStringTrueFalse(final Boolean bool) { + return toString(bool, "true", "false", null); + } + + /** + *

              Converts a Boolean to a String returning {@code 'on'}, + * {@code 'off'}, or {@code null}.

              + * + *
              +     *   BooleanUtils.toStringOnOff(Boolean.TRUE)  = "on"
              +     *   BooleanUtils.toStringOnOff(Boolean.FALSE) = "off"
              +     *   BooleanUtils.toStringOnOff(null)          = null;
              +     * 
              + * + * @param bool the Boolean to check + * @return {@code 'on'}, {@code 'off'}, or {@code null} + */ + public static String toStringOnOff(final Boolean bool) { + return toString(bool, "on", "off", null); + } + + /** + *

              Converts a Boolean to a String returning {@code 'yes'}, + * {@code 'no'}, or {@code null}.

              + * + *
              +     *   BooleanUtils.toStringYesNo(Boolean.TRUE)  = "yes"
              +     *   BooleanUtils.toStringYesNo(Boolean.FALSE) = "no"
              +     *   BooleanUtils.toStringYesNo(null)          = null;
              +     * 
              + * + * @param bool the Boolean to check + * @return {@code 'yes'}, {@code 'no'}, or {@code null} + */ + public static String toStringYesNo(final Boolean bool) { + return toString(bool, "yes", "no", null); + } + + /** + *

              Converts a Boolean to a String returning one of the input Strings.

              + * + *
              +     *   BooleanUtils.toString(Boolean.TRUE, "true", "false", null)   = "true"
              +     *   BooleanUtils.toString(Boolean.FALSE, "true", "false", null)  = "false"
              +     *   BooleanUtils.toString(null, "true", "false", null)           = null;
              +     * 
              + * + * @param bool the Boolean to check + * @param trueString the String to return if {@code true}, may be {@code null} + * @param falseString the String to return if {@code false}, may be {@code null} + * @param nullString the String to return if {@code null}, may be {@code null} + * @return one of the three input Strings + */ + public static String toString(final Boolean bool, final String trueString, final String falseString, final String nullString) { + if (bool == null) { + return nullString; + } + return bool.booleanValue() ? trueString : falseString; + } + + // boolean to String methods + //----------------------------------------------------------------------- + /** + *

              Converts a boolean to a String returning {@code 'true'} + * or {@code 'false'}.

              + * + *
              +     *   BooleanUtils.toStringTrueFalse(true)   = "true"
              +     *   BooleanUtils.toStringTrueFalse(false)  = "false"
              +     * 
              + * + * @param bool the Boolean to check + * @return {@code 'true'}, {@code 'false'}, or {@code null} + */ + public static String toStringTrueFalse(final boolean bool) { + return toString(bool, "true", "false"); + } + + /** + *

              Converts a boolean to a String returning {@code 'on'} + * or {@code 'off'}.

              + * + *
              +     *   BooleanUtils.toStringOnOff(true)   = "on"
              +     *   BooleanUtils.toStringOnOff(false)  = "off"
              +     * 
              + * + * @param bool the Boolean to check + * @return {@code 'on'}, {@code 'off'}, or {@code null} + */ + public static String toStringOnOff(final boolean bool) { + return toString(bool, "on", "off"); + } + + /** + *

              Converts a boolean to a String returning {@code 'yes'} + * or {@code 'no'}.

              + * + *
              +     *   BooleanUtils.toStringYesNo(true)   = "yes"
              +     *   BooleanUtils.toStringYesNo(false)  = "no"
              +     * 
              + * + * @param bool the Boolean to check + * @return {@code 'yes'}, {@code 'no'}, or {@code null} + */ + public static String toStringYesNo(final boolean bool) { + return toString(bool, "yes", "no"); + } + + /** + *

              Converts a boolean to a String returning one of the input Strings.

              + * + *
              +     *   BooleanUtils.toString(true, "true", "false")   = "true"
              +     *   BooleanUtils.toString(false, "true", "false")  = "false"
              +     * 
              + * + * @param bool the Boolean to check + * @param trueString the String to return if {@code true}, may be {@code null} + * @param falseString the String to return if {@code false}, may be {@code null} + * @return one of the two input Strings + */ + public static String toString(final boolean bool, final String trueString, final String falseString) { + return bool ? trueString : falseString; + } + + // logical operations + // ---------------------------------------------------------------------- + /** + *

              Performs an and on a set of booleans.

              + * + *
              +     *   BooleanUtils.and(true, true)         = true
              +     *   BooleanUtils.and(false, false)       = false
              +     *   BooleanUtils.and(true, false)        = false
              +     *   BooleanUtils.and(true, true, false)  = false
              +     *   BooleanUtils.and(true, true, true)   = true
              +     * 
              + * + * @param array an array of {@code boolean}s + * @return {@code true} if the and is successful. + * @throws IllegalArgumentException if {@code array} is {@code null} + * @throws IllegalArgumentException if {@code array} is empty. + * @since 3.0.1 + */ + public static boolean and(final boolean... array) { + // Validates input + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + if (array.length == 0) { + throw new IllegalArgumentException("Array is empty"); + } + for (final boolean element : array) { + if (!element) { + return false; + } + } + return true; + } + + /** + *

              Performs an and on an array of Booleans.

              + * + *
              +     *   BooleanUtils.and(Boolean.TRUE, Boolean.TRUE)                 = Boolean.TRUE
              +     *   BooleanUtils.and(Boolean.FALSE, Boolean.FALSE)               = Boolean.FALSE
              +     *   BooleanUtils.and(Boolean.TRUE, Boolean.FALSE)                = Boolean.FALSE
              +     *   BooleanUtils.and(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE)   = Boolean.TRUE
              +     *   BooleanUtils.and(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE) = Boolean.FALSE
              +     *   BooleanUtils.and(Boolean.TRUE, Boolean.FALSE, Boolean.TRUE)  = Boolean.FALSE
              +     * 
              + * + * @param array an array of {@code Boolean}s + * @return {@code true} if the and is successful. + * @throws IllegalArgumentException if {@code array} is {@code null} + * @throws IllegalArgumentException if {@code array} is empty. + * @throws IllegalArgumentException if {@code array} contains a {@code null} + * @since 3.0.1 + */ + public static Boolean and(final Boolean... array) { + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + if (array.length == 0) { + throw new IllegalArgumentException("Array is empty"); + } + try { + final boolean[] primitive = ArrayUtils.toPrimitive(array); + return and(primitive) ? Boolean.TRUE : Boolean.FALSE; + } catch (final NullPointerException ex) { + throw new IllegalArgumentException("The array must not contain any null elements"); + } + } + + /** + *

              Performs an or on a set of booleans.

              + * + *
              +     *   BooleanUtils.or(true, true)          = true
              +     *   BooleanUtils.or(false, false)        = false
              +     *   BooleanUtils.or(true, false)         = true
              +     *   BooleanUtils.or(true, true, false)   = true
              +     *   BooleanUtils.or(true, true, true)    = true
              +     *   BooleanUtils.or(false, false, false) = false
              +     * 
              + * + * @param array an array of {@code boolean}s + * @return {@code true} if the or is successful. + * @throws IllegalArgumentException if {@code array} is {@code null} + * @throws IllegalArgumentException if {@code array} is empty. + * @since 3.0.1 + */ + public static boolean or(final boolean... array) { + // Validates input + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + if (array.length == 0) { + throw new IllegalArgumentException("Array is empty"); + } + for (final boolean element : array) { + if (element) { + return true; + } + } + return false; + } + + /** + *

              Performs an or on an array of Booleans.

              + * + *
              +     *   BooleanUtils.or(Boolean.TRUE, Boolean.TRUE)                  = Boolean.TRUE
              +     *   BooleanUtils.or(Boolean.FALSE, Boolean.FALSE)                = Boolean.FALSE
              +     *   BooleanUtils.or(Boolean.TRUE, Boolean.FALSE)                 = Boolean.TRUE
              +     *   BooleanUtils.or(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE)    = Boolean.TRUE
              +     *   BooleanUtils.or(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE)  = Boolean.TRUE
              +     *   BooleanUtils.or(Boolean.TRUE, Boolean.FALSE, Boolean.TRUE)   = Boolean.TRUE
              +     *   BooleanUtils.or(Boolean.FALSE, Boolean.FALSE, Boolean.FALSE) = Boolean.FALSE
              +     * 
              + * + * @param array an array of {@code Boolean}s + * @return {@code true} if the or is successful. + * @throws IllegalArgumentException if {@code array} is {@code null} + * @throws IllegalArgumentException if {@code array} is empty. + * @throws IllegalArgumentException if {@code array} contains a {@code null} + * @since 3.0.1 + */ + public static Boolean or(final Boolean... array) { + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + if (array.length == 0) { + throw new IllegalArgumentException("Array is empty"); + } + try { + final boolean[] primitive = ArrayUtils.toPrimitive(array); + return or(primitive) ? Boolean.TRUE : Boolean.FALSE; + } catch (final NullPointerException ex) { + throw new IllegalArgumentException("The array must not contain any null elements"); + } + } + + /** + *

              Performs an xor on a set of booleans.

              + * + *
              +     *   BooleanUtils.xor(true, true)   = false
              +     *   BooleanUtils.xor(false, false) = false
              +     *   BooleanUtils.xor(true, false)  = true
              +     * 
              + * + * @param array an array of {@code boolean}s + * @return {@code true} if the xor is successful. + * @throws IllegalArgumentException if {@code array} is {@code null} + * @throws IllegalArgumentException if {@code array} is empty. + */ + public static boolean xor(final boolean... array) { + // Validates input + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + if (array.length == 0) { + throw new IllegalArgumentException("Array is empty"); + } + + // false if the neutral element of the xor operator + boolean result = false; + for (final boolean element : array) { + result ^= element; + } + + return result; + } + + /** + *

              Performs an xor on an array of Booleans.

              + * + *
              +     *   BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.TRUE })   = Boolean.FALSE
              +     *   BooleanUtils.xor(new Boolean[] { Boolean.FALSE, Boolean.FALSE }) = Boolean.FALSE
              +     *   BooleanUtils.xor(new Boolean[] { Boolean.TRUE, Boolean.FALSE })  = Boolean.TRUE
              +     * 
              + * + * @param array an array of {@code Boolean}s + * @return {@code true} if the xor is successful. + * @throws IllegalArgumentException if {@code array} is {@code null} + * @throws IllegalArgumentException if {@code array} is empty. + * @throws IllegalArgumentException if {@code array} contains a {@code null} + */ + public static Boolean xor(final Boolean... array) { + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + if (array.length == 0) { + throw new IllegalArgumentException("Array is empty"); + } + try { + final boolean[] primitive = ArrayUtils.toPrimitive(array); + return xor(primitive) ? Boolean.TRUE : Boolean.FALSE; + } catch (final NullPointerException ex) { + throw new IllegalArgumentException("The array must not contain any null elements"); + } + } + + /** + *

              Compares two {@code boolean} values. This is the same functionality as provided in Java 7.

              + * + * @param x the first {@code boolean} to compare + * @param y the second {@code boolean} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code !x && y}; and + * a value greater than {@code 0} if {@code x && !y} + * @since 3.4 + */ + public static int compare(final boolean x, final boolean y) { + if (x == y) { + return 0; + } + return x ? 1 : -1; + } + +} diff --git a/src/org/apache/commons/lang3/CharEncoding.java b/src/org/apache/commons/lang3/CharEncoding.java new file mode 100644 index 0000000..7fe9296 --- /dev/null +++ b/src/org/apache/commons/lang3/CharEncoding.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3; + +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; + +/** + *

              Character encoding names required of every implementation of the Java platform.

              + * + *

              According to JRE character + * encoding names:

              + * + *

              Every implementation of the Java platform is required to support the following character encodings. + * Consult the release documentation for your implementation to see if any other encodings are supported. + *

              + * + * @see JRE character encoding names + * @since 2.1 + */ +public class CharEncoding { + + /** + *

              ISO Latin Alphabet #1, also known as ISO-LATIN-1.

              + * + *

              Every implementation of the Java platform is required to support this character encoding.

              + */ + public static final String ISO_8859_1 = "ISO-8859-1"; + + /** + *

              Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block + * of the Unicode character set.

              + * + *

              Every implementation of the Java platform is required to support this character encoding.

              + */ + public static final String US_ASCII = "US-ASCII"; + + /** + *

              Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial + * byte-order mark (either order accepted on input, big-endian used on output).

              + * + *

              Every implementation of the Java platform is required to support this character encoding.

              + */ + public static final String UTF_16 = "UTF-16"; + + /** + *

              Sixteen-bit Unicode Transformation Format, big-endian byte order.

              + * + *

              Every implementation of the Java platform is required to support this character encoding.

              + */ + public static final String UTF_16BE = "UTF-16BE"; + + /** + *

              Sixteen-bit Unicode Transformation Format, little-endian byte order.

              + * + *

              Every implementation of the Java platform is required to support this character encoding.

              + */ + public static final String UTF_16LE = "UTF-16LE"; + + /** + *

              Eight-bit Unicode Transformation Format.

              + * + *

              Every implementation of the Java platform is required to support this character encoding.

              + */ + public static final String UTF_8 = "UTF-8"; + + /** + *

              Returns whether the named charset is supported.

              + * + *

              This is similar to + * java.nio.charset.Charset.isSupported(String) but handles more formats

              + * + * @param name the name of the requested charset; may be either a canonical name or an alias, null returns false + * @return {@code true} if the charset is available in the current Java virtual machine + */ + public static boolean isSupported(final String name) { + if (name == null) { + return false; + } + try { + return Charset.isSupported(name); + } catch (final IllegalCharsetNameException ex) { + return false; + } + } + +} diff --git a/src/org/apache/commons/lang3/CharRange.java b/src/org/apache/commons/lang3/CharRange.java new file mode 100644 index 0000000..2ccda7c --- /dev/null +++ b/src/org/apache/commons/lang3/CharRange.java @@ -0,0 +1,359 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + *

              A contiguous range of characters, optionally negated.

              + * + *

              Instances are immutable.

              + * + *

              #ThreadSafe#

              + * @since 1.0 + */ +// TODO: This is no longer public and will be removed later as CharSet is moved +// to depend on Range. +final class CharRange implements Iterable, Serializable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 8270183163158333422L; + + /** The first character, inclusive, in the range. */ + private final char start; + /** The last character, inclusive, in the range. */ + private final char end; + /** True if the range is everything except the characters specified. */ + private final boolean negated; + + /** Cached toString. */ + private transient String iToString; + + /** + *

              Constructs a {@code CharRange} over a set of characters, + * optionally negating the range.

              + * + *

              A negated range includes everything except that defined by the + * start and end characters.

              + * + *

              If start and end are in the wrong order, they are reversed. + * Thus {@code a-e} is the same as {@code e-a}.

              + * + * @param start first character, inclusive, in this range + * @param end last character, inclusive, in this range + * @param negated true to express everything except the range + */ + private CharRange(char start, char end, final boolean negated) { + super(); + if (start > end) { + final char temp = start; + start = end; + end = temp; + } + + this.start = start; + this.end = end; + this.negated = negated; + } + + /** + *

              Constructs a {@code CharRange} over a single character.

              + * + * @param ch only character in this range + * @return the new CharRange object + * @see CharRange#CharRange(char, char, boolean) + * @since 2.5 + */ + public static CharRange is(final char ch) { + return new CharRange(ch, ch, false); + } + + /** + *

              Constructs a negated {@code CharRange} over a single character.

              + * + * @param ch only character in this range + * @return the new CharRange object + * @see CharRange#CharRange(char, char, boolean) + * @since 2.5 + */ + public static CharRange isNot(final char ch) { + return new CharRange(ch, ch, true); + } + + /** + *

              Constructs a {@code CharRange} over a set of characters.

              + * + * @param start first character, inclusive, in this range + * @param end last character, inclusive, in this range + * @return the new CharRange object + * @see CharRange#CharRange(char, char, boolean) + * @since 2.5 + */ + public static CharRange isIn(final char start, final char end) { + return new CharRange(start, end, false); + } + + /** + *

              Constructs a negated {@code CharRange} over a set of characters.

              + * + * @param start first character, inclusive, in this range + * @param end last character, inclusive, in this range + * @return the new CharRange object + * @see CharRange#CharRange(char, char, boolean) + * @since 2.5 + */ + public static CharRange isNotIn(final char start, final char end) { + return new CharRange(start, end, true); + } + + // Accessors + //----------------------------------------------------------------------- + /** + *

              Gets the start character for this character range.

              + * + * @return the start char (inclusive) + */ + public char getStart() { + return this.start; + } + + /** + *

              Gets the end character for this character range.

              + * + * @return the end char (inclusive) + */ + public char getEnd() { + return this.end; + } + + /** + *

              Is this {@code CharRange} negated.

              + * + *

              A negated range includes everything except that defined by the + * start and end characters.

              + * + * @return {@code true} if negated + */ + public boolean isNegated() { + return negated; + } + + // Contains + //----------------------------------------------------------------------- + /** + *

              Is the character specified contained in this range.

              + * + * @param ch the character to check + * @return {@code true} if this range contains the input character + */ + public boolean contains(final char ch) { + return (ch >= start && ch <= end) != negated; + } + + /** + *

              Are all the characters of the passed in range contained in + * this range.

              + * + * @param range the range to check against + * @return {@code true} if this range entirely contains the input range + * @throws IllegalArgumentException if {@code null} input + */ + public boolean contains(final CharRange range) { + if (range == null) { + throw new IllegalArgumentException("The Range must not be null"); + } + if (negated) { + if (range.negated) { + return start >= range.start && end <= range.end; + } + return range.end < start || range.start > end; + } + if (range.negated) { + return start == 0 && end == Character.MAX_VALUE; + } + return start <= range.start && end >= range.end; + } + + // Basics + //----------------------------------------------------------------------- + /** + *

              Compares two CharRange objects, returning true if they represent + * exactly the same range of characters defined in the same way.

              + * + * @param obj the object to compare to + * @return true if equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CharRange == false) { + return false; + } + final CharRange other = (CharRange) obj; + return start == other.start && end == other.end && negated == other.negated; + } + + /** + *

              Gets a hashCode compatible with the equals method.

              + * + * @return a suitable hashCode + */ + @Override + public int hashCode() { + return 83 + start + 7 * end + (negated ? 1 : 0); + } + + /** + *

              Gets a string representation of the character range.

              + * + * @return string representation of this range + */ + @Override + public String toString() { + if (iToString == null) { + final StringBuilder buf = new StringBuilder(4); + if (isNegated()) { + buf.append('^'); + } + buf.append(start); + if (start != end) { + buf.append('-'); + buf.append(end); + } + iToString = buf.toString(); + } + return iToString; + } + + // Expansions + //----------------------------------------------------------------------- + /** + *

              Returns an iterator which can be used to walk through the characters described by this range.

              + * + *

              #NotThreadSafe# the iterator is not thread-safe

              + * @return an iterator to the chars represented by this range + * @since 2.5 + */ + @Override + public Iterator iterator() { + return new CharacterIterator(this); + } + + /** + * Character {@link Iterator}. + *

              #NotThreadSafe#

              + */ + private static class CharacterIterator implements Iterator { + /** The current character */ + private char current; + + private final CharRange range; + private boolean hasNext; + + /** + * Construct a new iterator for the character range. + * + * @param r The character range + */ + private CharacterIterator(final CharRange r) { + range = r; + hasNext = true; + + if (range.negated) { + if (range.start == 0) { + if (range.end == Character.MAX_VALUE) { + // This range is an empty set + hasNext = false; + } else { + current = (char) (range.end + 1); + } + } else { + current = 0; + } + } else { + current = range.start; + } + } + + /** + * Prepare the next character in the range. + */ + private void prepareNext() { + if (range.negated) { + if (current == Character.MAX_VALUE) { + hasNext = false; + } else if (current + 1 == range.start) { + if (range.end == Character.MAX_VALUE) { + hasNext = false; + } else { + current = (char) (range.end + 1); + } + } else { + current = (char) (current + 1); + } + } else if (current < range.end) { + current = (char) (current + 1); + } else { + hasNext = false; + } + } + + /** + * Has the iterator not reached the end character yet? + * + * @return {@code true} if the iterator has yet to reach the character date + */ + @Override + public boolean hasNext() { + return hasNext; + } + + /** + * Return the next character in the iteration + * + * @return {@code Character} for the next character + */ + @Override + public Character next() { + if (hasNext == false) { + throw new NoSuchElementException(); + } + final char cur = current; + prepareNext(); + return Character.valueOf(cur); + } + + /** + * Always throws UnsupportedOperationException. + * + * @throws UnsupportedOperationException + * @see java.util.Iterator#remove() + */ + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/src/org/apache/commons/lang3/CharSequenceUtils.java b/src/org/apache/commons/lang3/CharSequenceUtils.java new file mode 100644 index 0000000..e35f5aa --- /dev/null +++ b/src/org/apache/commons/lang3/CharSequenceUtils.java @@ -0,0 +1,306 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +/** + *

              Operations on {@link CharSequence} that are + * {@code null} safe.

              + * + * @see CharSequence + * @since 3.0 + */ +public class CharSequenceUtils { + + private static final int NOT_FOUND = -1; + + /** + *

              {@code CharSequenceUtils} instances should NOT be constructed in + * standard programming.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public CharSequenceUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

              Returns a new {@code CharSequence} that is a subsequence of this + * sequence starting with the {@code char} value at the specified index.

              + * + *

              This provides the {@code CharSequence} equivalent to {@link String#substring(int)}. + * The length (in {@code char}) of the returned sequence is {@code length() - start}, + * so if {@code start == end} then an empty sequence is returned.

              + * + * @param cs the specified subsequence, null returns null + * @param start the start index, inclusive, valid + * @return a new subsequence, may be null + * @throws IndexOutOfBoundsException if {@code start} is negative or if + * {@code start} is greater than {@code length()} + */ + public static CharSequence subSequence(final CharSequence cs, final int start) { + return cs == null ? null : cs.subSequence(start, cs.length()); + } + + //----------------------------------------------------------------------- + /** + * Returns the index within cs of the first occurrence of the + * specified character, starting the search at the specified index. + *

              + * If a character with value searchChar occurs in the + * character sequence represented by the cs + * object at an index no smaller than start, then + * the index of the first such occurrence is returned. For values + * of searchChar in the range from 0 to 0xFFFF (inclusive), + * this is the smallest value k such that: + *

              +     * (this.charAt(k) == searchChar) && (k >= start)
              +     * 
              + * is true. For other values of searchChar, it is the + * smallest value k such that: + *
              +     * (this.codePointAt(k) == searchChar) && (k >= start)
              +     * 
              + * is true. In either case, if no such character occurs inm cs + * at or after position start, then + * -1 is returned. + * + *

              + * There is no restriction on the value of start. If it + * is negative, it has the same effect as if it were zero: the entire + * CharSequence may be searched. If it is greater than + * the length of cs, it has the same effect as if it were + * equal to the length of cs: -1 is returned. + * + *

              All indices are specified in char values + * (Unicode code units). + * + * @param cs the {@code CharSequence} to be processed, not null + * @param searchChar the char to be searched for + * @param start the start index, negative starts at the string start + * @return the index where the search char was found, -1 if not found + * @since 3.6 updated to behave more like String + */ + static int indexOf(final CharSequence cs, final int searchChar, int start) { + if (cs instanceof String) { + return ((String) cs).indexOf(searchChar, start); + } + final int sz = cs.length(); + if (start < 0) { + start = 0; + } + if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + for (int i = start; i < sz; i++) { + if (cs.charAt(i) == searchChar) { + return i; + } + } + } + //supplementary characters (LANG1300) + if (searchChar <= Character.MAX_CODE_POINT) { + char[] chars = Character.toChars(searchChar); + for (int i = start; i < sz - 1; i++) { + char high = cs.charAt(i); + char low = cs.charAt(i + 1); + if (high == chars[0] && low == chars[1]) { + return i; + } + } + } + return NOT_FOUND; + } + + /** + * Used by the indexOf(CharSequence methods) as a green implementation of indexOf. + * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the {@code CharSequence} to be searched for + * @param start the start index + * @return the index where the search sequence was found + */ + static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) { + return cs.toString().indexOf(searchChar.toString(), start); +// if (cs instanceof String && searchChar instanceof String) { +// // TODO: Do we assume searchChar is usually relatively small; +// // If so then calling toString() on it is better than reverting to +// // the green implementation in the else block +// return ((String) cs).indexOf((String) searchChar, start); +// } else { +// // TODO: Implement rather than convert to String +// return cs.toString().indexOf(searchChar.toString(), start); +// } + } + + /** + * Returns the index within cs of the last occurrence of + * the specified character, searching backward starting at the + * specified index. For values of searchChar in the range + * from 0 to 0xFFFF (inclusive), the index returned is the largest + * value k such that: + *

              +     * (this.charAt(k) == searchChar) && (k <= start)
              +     * 
              + * is true. For other values of searchChar, it is the + * largest value k such that: + *
              +     * (this.codePointAt(k) == searchChar) && (k <= start)
              +     * 
              + * is true. In either case, if no such character occurs in cs + * at or before position start, then -1 is returned. + * + *

              All indices are specified in char values + * (Unicode code units). + * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the char to be searched for + * @param start the start index, negative returns -1, beyond length starts at end + * @return the index where the search char was found, -1 if not found + * @since 3.6 updated to behave more like String + */ + static int lastIndexOf(final CharSequence cs, final int searchChar, int start) { + if (cs instanceof String) { + return ((String) cs).lastIndexOf(searchChar, start); + } + final int sz = cs.length(); + if (start < 0) { + return NOT_FOUND; + } + if (start >= sz) { + start = sz - 1; + } + if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + for (int i = start; i >= 0; --i) { + if (cs.charAt(i) == searchChar) { + return i; + } + } + } + //supplementary characters (LANG1300) + //NOTE - we must do a forward traversal for this to avoid duplicating code points + if (searchChar <= Character.MAX_CODE_POINT) { + char[] chars = Character.toChars(searchChar); + //make sure it's not the last index + if (start == sz - 1) { + return NOT_FOUND; + } + for (int i = start; i >= 0; i--) { + char high = cs.charAt(i); + char low = cs.charAt(i + 1); + if (chars[0] == high && chars[1] == low) { + return i; + } + } + } + return NOT_FOUND; + } + + /** + * Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf + * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the {@code CharSequence} to be searched for + * @param start the start index + * @return the index where the search sequence was found + */ + static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, final int start) { + return cs.toString().lastIndexOf(searchChar.toString(), start); +// if (cs instanceof String && searchChar instanceof String) { +// // TODO: Do we assume searchChar is usually relatively small; +// // If so then calling toString() on it is better than reverting to +// // the green implementation in the else block +// return ((String) cs).lastIndexOf((String) searchChar, start); +// } else { +// // TODO: Implement rather than convert to String +// return cs.toString().lastIndexOf(searchChar.toString(), start); +// } + } + + /** + * Green implementation of toCharArray. + * + * @param cs the {@code CharSequence} to be processed + * @return the resulting char array + */ + static char[] toCharArray(final CharSequence cs) { + if (cs instanceof String) { + return ((String) cs).toCharArray(); + } + final int sz = cs.length(); + final char[] array = new char[cs.length()]; + for (int i = 0; i < sz; i++) { + array[i] = cs.charAt(i); + } + return array; + } + + /** + * Green implementation of regionMatches. + * + * @param cs the {@code CharSequence} to be processed + * @param ignoreCase whether or not to be case insensitive + * @param thisStart the index to start on the {@code cs} CharSequence + * @param substring the {@code CharSequence} to be looked for + * @param start the index to start on the {@code substring} CharSequence + * @param length character length of the region + * @return whether the region matched + */ + static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, + final CharSequence substring, final int start, final int length) { + if (cs instanceof String && substring instanceof String) { + return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length); + } + int index1 = thisStart; + int index2 = start; + int tmpLen = length; + + // Extract these first so we detect NPEs the same as the java.lang.String version + final int srcLen = cs.length() - thisStart; + final int otherLen = substring.length() - start; + + // Check for invalid parameters + if (thisStart < 0 || start < 0 || length < 0) { + return false; + } + + // Check that the regions are long enough + if (srcLen < length || otherLen < length) { + return false; + } + + while (tmpLen-- > 0) { + final char c1 = cs.charAt(index1++); + final char c2 = substring.charAt(index2++); + + if (c1 == c2) { + continue; + } + + if (!ignoreCase) { + return false; + } + + // The same check as in String.regionMatches(): + if (Character.toUpperCase(c1) != Character.toUpperCase(c2) + && Character.toLowerCase(c1) != Character.toLowerCase(c2)) { + return false; + } + } + + return true; + } +} diff --git a/src/org/apache/commons/lang3/CharSet.java b/src/org/apache/commons/lang3/CharSet.java new file mode 100644 index 0000000..150f850 --- /dev/null +++ b/src/org/apache/commons/lang3/CharSet.java @@ -0,0 +1,294 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + *

              A set of characters.

              + * + *

              Instances are immutable, but instances of subclasses may not be.

              + * + *

              #ThreadSafe#

              + * @since 1.0 + */ +public class CharSet implements Serializable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 5947847346149275958L; + + /** + * A CharSet defining no characters. + * @since 2.0 + */ + public static final CharSet EMPTY = new CharSet((String) null); + + /** + * A CharSet defining ASCII alphabetic characters "a-zA-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "a-z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z"); + + /** + * A CharSet defining ASCII alphabetic characters "A-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "0-9". + * @since 2.0 + */ + public static final CharSet ASCII_NUMERIC = new CharSet("0-9"); + + /** + * A Map of the common cases used in the factory. + * Subclasses can add more common patterns if desired + * @since 2.0 + */ + protected static final Map COMMON = Collections.synchronizedMap(new HashMap()); + + static { + COMMON.put(null, EMPTY); + COMMON.put(StringUtils.EMPTY, EMPTY); + COMMON.put("a-zA-Z", ASCII_ALPHA); + COMMON.put("A-Za-z", ASCII_ALPHA); + COMMON.put("a-z", ASCII_ALPHA_LOWER); + COMMON.put("A-Z", ASCII_ALPHA_UPPER); + COMMON.put("0-9", ASCII_NUMERIC); + } + + /** The set of CharRange objects. */ + private final Set set = Collections.synchronizedSet(new HashSet()); + + //----------------------------------------------------------------------- + /** + *

              Factory method to create a new CharSet using a special syntax.

              + * + *
                + *
              • {@code null} or empty string ("") + * - set containing no characters
              • + *
              • Single character, such as "a" + * - set containing just that character
              • + *
              • Multi character, such as "a-e" + * - set containing characters from one character to the other
              • + *
              • Negated, such as "^a" or "^a-e" + * - set containing all characters except those defined
              • + *
              • Combinations, such as "abe-g" + * - set containing all the characters from the individual sets
              • + *
              + * + *

              The matching order is:

              + *
                + *
              1. Negated multi character range, such as "^a-e" + *
              2. Ordinary multi character range, such as "a-e" + *
              3. Negated single character, such as "^a" + *
              4. Ordinary single character, such as "a" + *
              + * + *

              Matching works left to right. Once a match is found the + * search starts again from the next character.

              + * + *

              If the same range is defined twice using the same syntax, only + * one range will be kept. + * Thus, "a-ca-c" creates only one range of "a-c".

              + * + *

              If the start and end of a range are in the wrong order, + * they are reversed. Thus "a-e" is the same as "e-a". + * As a result, "a-ee-a" would create only one range, + * as the "a-e" and "e-a" are the same.

              + * + *

              The set of characters represented is the union of the specified ranges.

              + * + *

              There are two ways to add a literal negation character ({@code ^}):

              + *
                + *
              • As the last character in a string, e.g. {@code CharSet.getInstance("a-z^")}
              • + *
              • As a separate element, e.g. {@code CharSet.getInstance("^","a-z")}
              • + *
              + * + *

              Examples using the negation character:

              + *
              +     *     CharSet.getInstance("^a-c").contains('a') = false
              +     *     CharSet.getInstance("^a-c").contains('d') = true
              +     *     CharSet.getInstance("^^a-c").contains('a') = true // (only '^' is negated)
              +     *     CharSet.getInstance("^^a-c").contains('^') = false
              +     *     CharSet.getInstance("^a-cd-f").contains('d') = true 
              +     *     CharSet.getInstance("a-c^").contains('^') = true
              +     *     CharSet.getInstance("^", "a-c").contains('^') = true
              +     * 
              + * + *

              All CharSet objects returned by this method will be immutable.

              + * + * @param setStrs Strings to merge into the set, may be null + * @return a CharSet instance + * @since 2.4 + */ + public static CharSet getInstance(final String... setStrs) { + if (setStrs == null) { + return null; + } + if (setStrs.length == 1) { + final CharSet common = COMMON.get(setStrs[0]); + if (common != null) { + return common; + } + } + return new CharSet(setStrs); + } + + //----------------------------------------------------------------------- + /** + *

              Constructs a new CharSet using the set syntax. + * Each string is merged in with the set.

              + * + * @param set Strings to merge into the initial set + * @throws NullPointerException if set is {@code null} + */ + protected CharSet(final String... set) { + super(); + for (String s : set) { + add(s); + } + } + + //----------------------------------------------------------------------- + /** + *

              Add a set definition string to the {@code CharSet}.

              + * + * @param str set definition string + */ + protected void add(final String str) { + if (str == null) { + return; + } + + final int len = str.length(); + int pos = 0; + while (pos < len) { + final int remainder = len - pos; + if (remainder >= 4 && str.charAt(pos) == '^' && str.charAt(pos + 2) == '-') { + // negated range + set.add(CharRange.isNotIn(str.charAt(pos + 1), str.charAt(pos + 3))); + pos += 4; + } else if (remainder >= 3 && str.charAt(pos + 1) == '-') { + // range + set.add(CharRange.isIn(str.charAt(pos), str.charAt(pos + 2))); + pos += 3; + } else if (remainder >= 2 && str.charAt(pos) == '^') { + // negated char + set.add(CharRange.isNot(str.charAt(pos + 1))); + pos += 2; + } else { + // char + set.add(CharRange.is(str.charAt(pos))); + pos += 1; + } + } + } + + //----------------------------------------------------------------------- + /** + *

              Gets the internal set as an array of CharRange objects.

              + * + * @return an array of immutable CharRange objects + * @since 2.0 + */ +// NOTE: This is no longer public as CharRange is no longer a public class. +// It may be replaced when CharSet moves to Range. + /*public*/ CharRange[] getCharRanges() { + return set.toArray(new CharRange[set.size()]); + } + + //----------------------------------------------------------------------- + /** + *

              Does the {@code CharSet} contain the specified + * character {@code ch}.

              + * + * @param ch the character to check for + * @return {@code true} if the set contains the characters + */ + public boolean contains(final char ch) { + for (final CharRange range : set) { + if (range.contains(ch)) { + return true; + } + } + return false; + } + + // Basics + //----------------------------------------------------------------------- + /** + *

              Compares two {@code CharSet} objects, returning true if they represent + * exactly the same set of characters defined in the same way.

              + * + *

              The two sets {@code abc} and {@code a-c} are not + * equal according to this method.

              + * + * @param obj the object to compare to + * @return true if equal + * @since 2.0 + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CharSet == false) { + return false; + } + final CharSet other = (CharSet) obj; + return set.equals(other.set); + } + + /** + *

              Gets a hash code compatible with the equals method.

              + * + * @return a suitable hash code + * @since 2.0 + */ + @Override + public int hashCode() { + return 89 + set.hashCode(); + } + + /** + *

              Gets a string representation of the set.

              + * + * @return string representation of the set + */ + @Override + public String toString() { + return set.toString(); + } + +} diff --git a/src/org/apache/commons/lang3/CharSetUtils.java b/src/org/apache/commons/lang3/CharSetUtils.java new file mode 100644 index 0000000..84c1d09 --- /dev/null +++ b/src/org/apache/commons/lang3/CharSetUtils.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +/** + *

              Operations on {@code CharSet} instances.

              + * + *

              This class handles {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

              + * + *

              #ThreadSafe#

              + * @see CharSet + * @since 1.0 + */ +public class CharSetUtils { + + /** + *

              CharSetUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharSetUtils.evaluateSet(null);}.

              + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate.

              + */ + public CharSetUtils() { + super(); + } + + // Squeeze + //----------------------------------------------------------------------- + /** + *

              Squeezes any repetitions of a character that is mentioned in the + * supplied set.

              + * + *
              +     * CharSetUtils.squeeze(null, *)        = null
              +     * CharSetUtils.squeeze("", *)          = ""
              +     * CharSetUtils.squeeze(*, null)        = *
              +     * CharSetUtils.squeeze(*, "")          = *
              +     * CharSetUtils.squeeze("hello", "k-p") = "helo"
              +     * CharSetUtils.squeeze("hello", "a-e") = "hello"
              +     * 
              + * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str the string to squeeze, may be null + * @param set the character set to use for manipulation, may be null + * @return the modified String, {@code null} if null string input + */ + public static String squeeze(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return str; + } + final CharSet chars = CharSet.getInstance(set); + final StringBuilder buffer = new StringBuilder(str.length()); + final char[] chrs = str.toCharArray(); + final int sz = chrs.length; + char lastChar = chrs[0]; + char ch = ' '; + Character inChars = null; + Character notInChars = null; + buffer.append(lastChar); + for (int i = 1; i < sz; i++) { + ch = chrs[i]; + if (ch == lastChar) { + if (inChars != null && ch == inChars) { + continue; + } else { + if (notInChars == null || ch != notInChars) { + if (chars.contains(ch)) { + inChars = ch; + continue; + } else { + notInChars = ch; + } + } + } + } + buffer.append(ch); + lastChar = ch; + } + return buffer.toString(); + } + + // ContainsAny + //----------------------------------------------------------------------- + /** + *

              Takes an argument in set-syntax, see evaluateSet, + * and identifies whether any of the characters are present in the specified string.

              + * + *
              +     * CharSetUtils.containsAny(null, *)        = false
              +     * CharSetUtils.containsAny("", *)          = false
              +     * CharSetUtils.containsAny(*, null)        = false
              +     * CharSetUtils.containsAny(*, "")          = false
              +     * CharSetUtils.containsAny("hello", "k-p") = true
              +     * CharSetUtils.containsAny("hello", "a-d") = false
              +     * 
              + * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to look for characters in, may be null + * @param set String[] set of characters to identify, may be null + * @return whether or not the characters in the set are in the primary string + * @since 3.2 + */ + public static boolean containsAny(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return false; + } + final CharSet chars = CharSet.getInstance(set); + for (final char c : str.toCharArray()) { + if (chars.contains(c)) { + return true; + } + } + return false; + } + + // Count + //----------------------------------------------------------------------- + /** + *

              Takes an argument in set-syntax, see evaluateSet, + * and returns the number of characters present in the specified string.

              + * + *
              +     * CharSetUtils.count(null, *)        = 0
              +     * CharSetUtils.count("", *)          = 0
              +     * CharSetUtils.count(*, null)        = 0
              +     * CharSetUtils.count(*, "")          = 0
              +     * CharSetUtils.count("hello", "k-p") = 3
              +     * CharSetUtils.count("hello", "a-e") = 1
              +     * 
              + * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to count characters in, may be null + * @param set String[] set of characters to count, may be null + * @return the character count, zero if null string input + */ + public static int count(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return 0; + } + final CharSet chars = CharSet.getInstance(set); + int count = 0; + for (final char c : str.toCharArray()) { + if (chars.contains(c)) { + count++; + } + } + return count; + } + + // Keep + //----------------------------------------------------------------------- + /** + *

              Takes an argument in set-syntax, see evaluateSet, + * and keeps any of characters present in the specified string.

              + * + *
              +     * CharSetUtils.keep(null, *)        = null
              +     * CharSetUtils.keep("", *)          = ""
              +     * CharSetUtils.keep(*, null)        = ""
              +     * CharSetUtils.keep(*, "")          = ""
              +     * CharSetUtils.keep("hello", "hl")  = "hll"
              +     * CharSetUtils.keep("hello", "le")  = "ell"
              +     * 
              + * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to keep characters from, may be null + * @param set String[] set of characters to keep, may be null + * @return the modified String, {@code null} if null string input + * @since 2.0 + */ + public static String keep(final String str, final String... set) { + if (str == null) { + return null; + } + if (str.isEmpty() || deepEmpty(set)) { + return StringUtils.EMPTY; + } + return modify(str, set, true); + } + + // Delete + //----------------------------------------------------------------------- + /** + *

              Takes an argument in set-syntax, see evaluateSet, + * and deletes any of characters present in the specified string.

              + * + *
              +     * CharSetUtils.delete(null, *)        = null
              +     * CharSetUtils.delete("", *)          = ""
              +     * CharSetUtils.delete(*, null)        = *
              +     * CharSetUtils.delete(*, "")          = *
              +     * CharSetUtils.delete("hello", "hl")  = "eo"
              +     * CharSetUtils.delete("hello", "le")  = "ho"
              +     * 
              + * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to delete characters from, may be null + * @param set String[] set of characters to delete, may be null + * @return the modified String, {@code null} if null string input + */ + public static String delete(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return str; + } + return modify(str, set, false); + } + + //----------------------------------------------------------------------- + /** + * Implementation of delete and keep + * + * @param str String to modify characters within + * @param set String[] set of characters to modify + * @param expect whether to evaluate on match, or non-match + * @return the modified String, not null + */ + private static String modify(final String str, final String[] set, final boolean expect) { + final CharSet chars = CharSet.getInstance(set); + final StringBuilder buffer = new StringBuilder(str.length()); + final char[] chrs = str.toCharArray(); + for (char chr : chrs) { + if (chars.contains(chr) == expect) { + buffer.append(chr); + } + } + return buffer.toString(); + } + + /** + * Determines whether or not all the Strings in an array are + * empty or not. + * + * @param strings String[] whose elements are being checked for emptiness + * @return whether or not the String is empty + */ + private static boolean deepEmpty(final String[] strings) { + if (strings != null) { + for (final String s : strings) { + if (StringUtils.isNotEmpty(s)) { + return false; + } + } + } + return true; + } +} diff --git a/src/org/apache/commons/lang3/CharUtils.java b/src/org/apache/commons/lang3/CharUtils.java new file mode 100644 index 0000000..92a8d44 --- /dev/null +++ b/src/org/apache/commons/lang3/CharUtils.java @@ -0,0 +1,552 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +/** + *

              Operations on char primitives and Character objects.

              + * + *

              This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

              + * + *

              #ThreadSafe#

              + * @since 2.1 + */ +public class CharUtils { + + private static final String[] CHAR_STRING_ARRAY = new String[128]; + + private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /** + * {@code \u000a} linefeed LF ('\n'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char LF = '\n'; + + /** + * {@code \u000d} carriage return CR ('\r'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char CR = '\r'; + + + static { + for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { + CHAR_STRING_ARRAY[c] = String.valueOf(c); + } + } + + /** + *

              {@code CharUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharUtils.toString('c');}.

              + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate.

              + */ + public CharUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

              Converts the character to a Character.

              + * + *

              For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

              + * + *
              +     *   CharUtils.toCharacterObject(' ')  = ' '
              +     *   CharUtils.toCharacterObject('A')  = 'A'
              +     * 
              + * + * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127. + * @param ch the character to convert + * @return a Character of the specified character + */ + @Deprecated + public static Character toCharacterObject(final char ch) { + return Character.valueOf(ch); + } + + /** + *

              Converts the String to a Character using the first character, returning + * null for empty Strings.

              + * + *

              For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

              + * + *
              +     *   CharUtils.toCharacterObject(null) = null
              +     *   CharUtils.toCharacterObject("")   = null
              +     *   CharUtils.toCharacterObject("A")  = 'A'
              +     *   CharUtils.toCharacterObject("BA") = 'B'
              +     * 
              + * + * @param str the character to convert + * @return the Character value of the first letter of the String + */ + public static Character toCharacterObject(final String str) { + if (StringUtils.isEmpty(str)) { + return null; + } + return Character.valueOf(str.charAt(0)); + } + + //----------------------------------------------------------------------- + /** + *

              Converts the Character to a char throwing an exception for {@code null}.

              + * + *
              +     *   CharUtils.toChar(' ')  = ' '
              +     *   CharUtils.toChar('A')  = 'A'
              +     *   CharUtils.toChar(null) throws IllegalArgumentException
              +     * 
              + * + * @param ch the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException if the Character is null + */ + public static char toChar(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The Character must not be null"); + } + return ch.charValue(); + } + + /** + *

              Converts the Character to a char handling {@code null}.

              + * + *
              +     *   CharUtils.toChar(null, 'X') = 'X'
              +     *   CharUtils.toChar(' ', 'X')  = ' '
              +     *   CharUtils.toChar('A', 'X')  = 'A'
              +     * 
              + * + * @param ch the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the Character or the default if null + */ + public static char toChar(final Character ch, final char defaultValue) { + if (ch == null) { + return defaultValue; + } + return ch.charValue(); + } + + //----------------------------------------------------------------------- + /** + *

              Converts the String to a char using the first character, throwing + * an exception on empty Strings.

              + * + *
              +     *   CharUtils.toChar("A")  = 'A'
              +     *   CharUtils.toChar("BA") = 'B'
              +     *   CharUtils.toChar(null) throws IllegalArgumentException
              +     *   CharUtils.toChar("")   throws IllegalArgumentException
              +     * 
              + * + * @param str the character to convert + * @return the char value of the first letter of the String + * @throws IllegalArgumentException if the String is empty + */ + public static char toChar(final String str) { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException("The String must not be empty"); + } + return str.charAt(0); + } + + /** + *

              Converts the String to a char using the first character, defaulting + * the value on empty Strings.

              + * + *
              +     *   CharUtils.toChar(null, 'X') = 'X'
              +     *   CharUtils.toChar("", 'X')   = 'X'
              +     *   CharUtils.toChar("A", 'X')  = 'A'
              +     *   CharUtils.toChar("BA", 'X') = 'B'
              +     * 
              + * + * @param str the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the first letter of the String or the default if null + */ + public static char toChar(final String str, final char defaultValue) { + if (StringUtils.isEmpty(str)) { + return defaultValue; + } + return str.charAt(0); + } + + //----------------------------------------------------------------------- + /** + *

              Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

              + * + *

              This method coverts the char '1' to the int 1 and so on.

              + * + *
              +     *   CharUtils.toIntValue('3')  = 3
              +     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
              +     * 
              + * + * @param ch the character to convert + * @return the int value of the character + * @throws IllegalArgumentException if the character is not ASCII numeric + */ + public static int toIntValue(final char ch) { + if (isAsciiNumeric(ch) == false) { + throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); + } + return ch - 48; + } + + /** + *

              Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

              + * + *

              This method coverts the char '1' to the int 1 and so on.

              + * + *
              +     *   CharUtils.toIntValue('3', -1)  = 3
              +     *   CharUtils.toIntValue('A', -1)  = -1
              +     * 
              + * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final char ch, final int defaultValue) { + if (isAsciiNumeric(ch) == false) { + return defaultValue; + } + return ch - 48; + } + + /** + *

              Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

              + * + *

              This method coverts the char '1' to the int 1 and so on.

              + * + *
              +     *   CharUtils.toIntValue('3')  = 3
              +     *   CharUtils.toIntValue(null) throws IllegalArgumentException
              +     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
              +     * 
              + * + * @param ch the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException if the Character is not ASCII numeric or is null + */ + public static int toIntValue(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The character must not be null"); + } + return toIntValue(ch.charValue()); + } + + /** + *

              Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

              + * + *

              This method coverts the char '1' to the int 1 and so on.

              + * + *
              +     *   CharUtils.toIntValue(null, -1) = -1
              +     *   CharUtils.toIntValue('3', -1)  = 3
              +     *   CharUtils.toIntValue('A', -1)  = -1
              +     * 
              + * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final Character ch, final int defaultValue) { + if (ch == null) { + return defaultValue; + } + return toIntValue(ch.charValue(), defaultValue); + } + + //----------------------------------------------------------------------- + /** + *

              Converts the character to a String that contains the one character.

              + * + *

              For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

              + * + *
              +     *   CharUtils.toString(' ')  = " "
              +     *   CharUtils.toString('A')  = "A"
              +     * 
              + * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final char ch) { + if (ch < 128) { + return CHAR_STRING_ARRAY[ch]; + } + return new String(new char[] {ch}); + } + + /** + *

              Converts the character to a String that contains the one character.

              + * + *

              For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

              + * + *

              If {@code null} is passed in, {@code null} will be returned.

              + * + *
              +     *   CharUtils.toString(null) = null
              +     *   CharUtils.toString(' ')  = " "
              +     *   CharUtils.toString('A')  = "A"
              +     * 
              + * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final Character ch) { + if (ch == null) { + return null; + } + return toString(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

              Converts the string to the Unicode format '\u0020'.

              + * + *

              This format is the Java source code format.

              + * + *
              +     *   CharUtils.unicodeEscaped(' ') = "\u0020"
              +     *   CharUtils.unicodeEscaped('A') = "\u0041"
              +     * 
              + * + * @param ch the character to convert + * @return the escaped Unicode string + */ + public static String unicodeEscaped(final char ch) { + final StringBuilder sb = new StringBuilder(6); + sb.append("\\u"); + sb.append(HEX_DIGITS[(ch >> 12) & 15]); + sb.append(HEX_DIGITS[(ch >> 8) & 15]); + sb.append(HEX_DIGITS[(ch >> 4) & 15]); + sb.append(HEX_DIGITS[(ch) & 15]); + return sb.toString(); + } + + /** + *

              Converts the string to the Unicode format '\u0020'.

              + * + *

              This format is the Java source code format.

              + * + *

              If {@code null} is passed in, {@code null} will be returned.

              + * + *
              +     *   CharUtils.unicodeEscaped(null) = null
              +     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
              +     *   CharUtils.unicodeEscaped('A')  = "\u0041"
              +     * 
              + * + * @param ch the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ + public static String unicodeEscaped(final Character ch) { + if (ch == null) { + return null; + } + return unicodeEscaped(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

              Checks whether the character is ASCII 7 bit.

              + * + *
              +     *   CharUtils.isAscii('a')  = true
              +     *   CharUtils.isAscii('A')  = true
              +     *   CharUtils.isAscii('3')  = true
              +     *   CharUtils.isAscii('-')  = true
              +     *   CharUtils.isAscii('\n') = true
              +     *   CharUtils.isAscii('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if less than 128 + */ + public static boolean isAscii(final char ch) { + return ch < 128; + } + + /** + *

              Checks whether the character is ASCII 7 bit printable.

              + * + *
              +     *   CharUtils.isAsciiPrintable('a')  = true
              +     *   CharUtils.isAsciiPrintable('A')  = true
              +     *   CharUtils.isAsciiPrintable('3')  = true
              +     *   CharUtils.isAsciiPrintable('-')  = true
              +     *   CharUtils.isAsciiPrintable('\n') = false
              +     *   CharUtils.isAsciiPrintable('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if between 32 and 126 inclusive + */ + public static boolean isAsciiPrintable(final char ch) { + return ch >= 32 && ch < 127; + } + + /** + *

              Checks whether the character is ASCII 7 bit control.

              + * + *
              +     *   CharUtils.isAsciiControl('a')  = false
              +     *   CharUtils.isAsciiControl('A')  = false
              +     *   CharUtils.isAsciiControl('3')  = false
              +     *   CharUtils.isAsciiControl('-')  = false
              +     *   CharUtils.isAsciiControl('\n') = true
              +     *   CharUtils.isAsciiControl('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if less than 32 or equals 127 + */ + public static boolean isAsciiControl(final char ch) { + return ch < 32 || ch == 127; + } + + /** + *

              Checks whether the character is ASCII 7 bit alphabetic.

              + * + *
              +     *   CharUtils.isAsciiAlpha('a')  = true
              +     *   CharUtils.isAsciiAlpha('A')  = true
              +     *   CharUtils.isAsciiAlpha('3')  = false
              +     *   CharUtils.isAsciiAlpha('-')  = false
              +     *   CharUtils.isAsciiAlpha('\n') = false
              +     *   CharUtils.isAsciiAlpha('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if between 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlpha(final char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + /** + *

              Checks whether the character is ASCII 7 bit alphabetic upper case.

              + * + *
              +     *   CharUtils.isAsciiAlphaUpper('a')  = false
              +     *   CharUtils.isAsciiAlphaUpper('A')  = true
              +     *   CharUtils.isAsciiAlphaUpper('3')  = false
              +     *   CharUtils.isAsciiAlphaUpper('-')  = false
              +     *   CharUtils.isAsciiAlphaUpper('\n') = false
              +     *   CharUtils.isAsciiAlphaUpper('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if between 65 and 90 inclusive + */ + public static boolean isAsciiAlphaUpper(final char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + /** + *

              Checks whether the character is ASCII 7 bit alphabetic lower case.

              + * + *
              +     *   CharUtils.isAsciiAlphaLower('a')  = true
              +     *   CharUtils.isAsciiAlphaLower('A')  = false
              +     *   CharUtils.isAsciiAlphaLower('3')  = false
              +     *   CharUtils.isAsciiAlphaLower('-')  = false
              +     *   CharUtils.isAsciiAlphaLower('\n') = false
              +     *   CharUtils.isAsciiAlphaLower('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if between 97 and 122 inclusive + */ + public static boolean isAsciiAlphaLower(final char ch) { + return ch >= 'a' && ch <= 'z'; + } + + /** + *

              Checks whether the character is ASCII 7 bit numeric.

              + * + *
              +     *   CharUtils.isAsciiNumeric('a')  = false
              +     *   CharUtils.isAsciiNumeric('A')  = false
              +     *   CharUtils.isAsciiNumeric('3')  = true
              +     *   CharUtils.isAsciiNumeric('-')  = false
              +     *   CharUtils.isAsciiNumeric('\n') = false
              +     *   CharUtils.isAsciiNumeric('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if between 48 and 57 inclusive + */ + public static boolean isAsciiNumeric(final char ch) { + return ch >= '0' && ch <= '9'; + } + + /** + *

              Checks whether the character is ASCII 7 bit numeric.

              + * + *
              +     *   CharUtils.isAsciiAlphanumeric('a')  = true
              +     *   CharUtils.isAsciiAlphanumeric('A')  = true
              +     *   CharUtils.isAsciiAlphanumeric('3')  = true
              +     *   CharUtils.isAsciiAlphanumeric('-')  = false
              +     *   CharUtils.isAsciiAlphanumeric('\n') = false
              +     *   CharUtils.isAsciiAlphanumeric('©') = false
              +     * 
              + * + * @param ch the character to check + * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlphanumeric(final char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + *

              Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

              + * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(final char x, final char y) { + return x-y; + } +} diff --git a/src/org/apache/commons/lang3/ClassPathUtils.java b/src/org/apache/commons/lang3/ClassPathUtils.java new file mode 100644 index 0000000..df3773a --- /dev/null +++ b/src/org/apache/commons/lang3/ClassPathUtils.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +/** + * Operations regarding the classpath. + * + *

              The methods of this class do not allow {@code null} inputs.

              + * + * @since 3.3 + */ +//@Immutable +public class ClassPathUtils { + + /** + *

              {@code ClassPathUtils} instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * {@code ClassPathUtils.toFullyQualifiedName(MyClass.class, "MyClass.properties");}.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public ClassPathUtils() { + super(); + } + + /** + * Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context. + * + *

              Note that this method does not check whether the resource actually exists. + * It only constructs the name. + * Null inputs are not allowed.

              + * + *
              +     * ClassPathUtils.toFullyQualifiedName(StringUtils.class, "StringUtils.properties") = "org.apache.commons.lang3.StringUtils.properties"
              +     * 
              + * + * @param context The context for constructing the name. + * @param resourceName the resource name to construct the fully qualified name for. + * @return the fully qualified name of the resource with name {@code resourceName}. + * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null. + */ + public static String toFullyQualifiedName(final Class context, final String resourceName) { + Validate.notNull(context, "Parameter '%s' must not be null!", "context" ); + Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName"); + return toFullyQualifiedName(context.getPackage(), resourceName); + } + + /** + * Returns the fully qualified name for the resource with name {@code resourceName} relative to the given context. + * + *

              Note that this method does not check whether the resource actually exists. + * It only constructs the name. + * Null inputs are not allowed.

              + * + *
              +     * ClassPathUtils.toFullyQualifiedName(StringUtils.class.getPackage(), "StringUtils.properties") = "org.apache.commons.lang3.StringUtils.properties"
              +     * 
              + * + * @param context The context for constructing the name. + * @param resourceName the resource name to construct the fully qualified name for. + * @return the fully qualified name of the resource with name {@code resourceName}. + * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null. + */ + public static String toFullyQualifiedName(final Package context, final String resourceName) { + Validate.notNull(context, "Parameter '%s' must not be null!", "context" ); + Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName"); + return context.getName() + "." + resourceName; + } + + /** + * Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context. + * + *

              Note that this method does not check whether the resource actually exists. + * It only constructs the path. + * Null inputs are not allowed.

              + * + *
              +     * ClassPathUtils.toFullyQualifiedPath(StringUtils.class, "StringUtils.properties") = "org/apache/commons/lang3/StringUtils.properties"
              +     * 
              + * + * @param context The context for constructing the path. + * @param resourceName the resource name to construct the fully qualified path for. + * @return the fully qualified path of the resource with name {@code resourceName}. + * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null. + */ + public static String toFullyQualifiedPath(final Class context, final String resourceName) { + Validate.notNull(context, "Parameter '%s' must not be null!", "context" ); + Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName"); + return toFullyQualifiedPath(context.getPackage(), resourceName); + } + + + /** + * Returns the fully qualified path for the resource with name {@code resourceName} relative to the given context. + * + *

              Note that this method does not check whether the resource actually exists. + * It only constructs the path. + * Null inputs are not allowed.

              + * + *
              +     * ClassPathUtils.toFullyQualifiedPath(StringUtils.class.getPackage(), "StringUtils.properties") = "org/apache/commons/lang3/StringUtils.properties"
              +     * 
              + * + * @param context The context for constructing the path. + * @param resourceName the resource name to construct the fully qualified path for. + * @return the fully qualified path of the resource with name {@code resourceName}. + * @throws java.lang.NullPointerException if either {@code context} or {@code resourceName} is null. + */ + public static String toFullyQualifiedPath(final Package context, final String resourceName) { + Validate.notNull(context, "Parameter '%s' must not be null!", "context" ); + Validate.notNull(resourceName, "Parameter '%s' must not be null!", "resourceName"); + return context.getName().replace('.', '/') + "/" + resourceName; + } + +} diff --git a/src/org/apache/commons/lang3/ClassUtils.java b/src/org/apache/commons/lang3/ClassUtils.java new file mode 100644 index 0000000..012d2a6 --- /dev/null +++ b/src/org/apache/commons/lang3/ClassUtils.java @@ -0,0 +1,1334 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.mutable.MutableObject; + +/** + *

              Operates on classes without using reflection.

              + * + *

              This class handles invalid {@code null} inputs as best it can. + * Each method documents its behaviour in more detail.

              + * + *

              The notion of a {@code canonical name} includes the human + * readable name for the type, for example {@code int[]}. The + * non-canonical method variants work with the JVM names, such as + * {@code [I}.

              + * + * @since 2.0 + */ +public class ClassUtils { + /** + * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}. + * @since 3.2 + */ + public enum Interfaces { + INCLUDE, EXCLUDE + } + + /** + * The package separator character: '.' == {@value}. + */ + public static final char PACKAGE_SEPARATOR_CHAR = '.'; + + /** + * The package separator String: ".". + */ + public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); + + /** + * The inner class separator character: '$' == {@value}. + */ + public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; + + /** + * The inner class separator String: {@code "$"}. + */ + public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); + + /** + * Maps names of primitives to their corresponding primitive {@code Class}es. + */ + private static final Map> namePrimitiveMap = new HashMap<>(); + static { + namePrimitiveMap.put("boolean", Boolean.TYPE); + namePrimitiveMap.put("byte", Byte.TYPE); + namePrimitiveMap.put("char", Character.TYPE); + namePrimitiveMap.put("short", Short.TYPE); + namePrimitiveMap.put("int", Integer.TYPE); + namePrimitiveMap.put("long", Long.TYPE); + namePrimitiveMap.put("double", Double.TYPE); + namePrimitiveMap.put("float", Float.TYPE); + namePrimitiveMap.put("void", Void.TYPE); + } + + /** + * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}. + */ + private static final Map, Class> primitiveWrapperMap = new HashMap<>(); + static { + primitiveWrapperMap.put(Boolean.TYPE, Boolean.class); + primitiveWrapperMap.put(Byte.TYPE, Byte.class); + primitiveWrapperMap.put(Character.TYPE, Character.class); + primitiveWrapperMap.put(Short.TYPE, Short.class); + primitiveWrapperMap.put(Integer.TYPE, Integer.class); + primitiveWrapperMap.put(Long.TYPE, Long.class); + primitiveWrapperMap.put(Double.TYPE, Double.class); + primitiveWrapperMap.put(Float.TYPE, Float.class); + primitiveWrapperMap.put(Void.TYPE, Void.TYPE); + } + + /** + * Maps wrapper {@code Class}es to their corresponding primitive types. + */ + private static final Map, Class> wrapperPrimitiveMap = new HashMap<>(); + static { + for (final Map.Entry, Class> entry : primitiveWrapperMap.entrySet()) { + final Class primitiveClass = entry.getKey(); + final Class wrapperClass = entry.getValue(); + if (!primitiveClass.equals(wrapperClass)) { + wrapperPrimitiveMap.put(wrapperClass, primitiveClass); + } + } + } + + /** + * Maps a primitive class name to its corresponding abbreviation used in array class names. + */ + private static final Map abbreviationMap; + + /** + * Maps an abbreviation used in array class names to corresponding primitive class name. + */ + private static final Map reverseAbbreviationMap; + + /** + * Feed abbreviation maps + */ + static { + final Map m = new HashMap<>(); + m.put("int", "I"); + m.put("boolean", "Z"); + m.put("float", "F"); + m.put("long", "J"); + m.put("short", "S"); + m.put("byte", "B"); + m.put("double", "D"); + m.put("char", "C"); + final Map r = new HashMap<>(); + for (final Map.Entry e : m.entrySet()) { + r.put(e.getValue(), e.getKey()); + } + abbreviationMap = Collections.unmodifiableMap(m); + reverseAbbreviationMap = Collections.unmodifiableMap(r); + } + + /** + *

              ClassUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code ClassUtils.getShortClassName(cls)}.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public ClassUtils() { + super(); + } + + // Short class name + // ---------------------------------------------------------------------- + /** + *

              Gets the class name minus the package name for an {@code Object}.

              + * + * @param object the class to get the short name for, may be null + * @param valueIfNull the value to return if null + * @return the class name of the object without the package name, or the null value + */ + public static String getShortClassName(final Object object, final String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getShortClassName(object.getClass()); + } + + /** + *

              Gets the class name minus the package name from a {@code Class}.

              + * + *

              Consider using the Java 5 API {@link Class#getSimpleName()} instead. + * The one known difference is that this code will return {@code "Map.Entry"} while + * the {@code java.lang.Class} variant will simply return {@code "Entry"}.

              + * + * @param cls the class to get the short name for. + * @return the class name without the package name or an empty string + */ + public static String getShortClassName(final Class cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getShortClassName(cls.getName()); + } + + /** + *

              Gets the class name minus the package name from a String.

              + * + *

              The string passed in is assumed to be a class name - it is not checked.

              + + *

              Note that this method differs from Class.getSimpleName() in that this will + * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply + * return {@code "Entry"}.

              + * + * @param className the className to get the short name for + * @return the class name of the class without the package name or an empty string + */ + public static String getShortClassName(String className) { + if (StringUtils.isEmpty(className)) { + return StringUtils.EMPTY; + } + + final StringBuilder arrayPrefix = new StringBuilder(); + + // Handle array encoding + if (className.startsWith("[")) { + while (className.charAt(0) == '[') { + className = className.substring(1); + arrayPrefix.append("[]"); + } + // Strip Object type encoding + if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { + className = className.substring(1, className.length() - 1); + } + + if (reverseAbbreviationMap.containsKey(className)) { + className = reverseAbbreviationMap.get(className); + } + } + + final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + final int innerIdx = className.indexOf( + INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1); + String out = className.substring(lastDotIdx + 1); + if (innerIdx != -1) { + out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR); + } + return out + arrayPrefix; + } + + /** + *

              Null-safe version of aClass.getSimpleName()

              + * + * @param cls the class for which to get the simple name. + * @return the simple class name. + * @since 3.0 + * @see Class#getSimpleName() + */ + public static String getSimpleName(final Class cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return cls.getSimpleName(); + } + + /** + *

              Null-safe version of aClass.getSimpleName()

              + * + * @param object the object for which to get the simple class name. + * @param valueIfNull the value to return if object is null + * @return the simple class name. + * @since 3.0 + * @see Class#getSimpleName() + */ + public static String getSimpleName(final Object object, final String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getSimpleName(object.getClass()); + } + + // Package name + // ---------------------------------------------------------------------- + /** + *

              Gets the package name of an {@code Object}.

              + * + * @param object the class to get the package name for, may be null + * @param valueIfNull the value to return if null + * @return the package name of the object, or the null value + */ + public static String getPackageName(final Object object, final String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getPackageName(object.getClass()); + } + + /** + *

              Gets the package name of a {@code Class}.

              + * + * @param cls the class to get the package name for, may be {@code null}. + * @return the package name or an empty string + */ + public static String getPackageName(final Class cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getPackageName(cls.getName()); + } + + /** + *

              Gets the package name from a {@code String}.

              + * + *

              The string passed in is assumed to be a class name - it is not checked.

              + *

              If the class is unpackaged, return an empty string.

              + * + * @param className the className to get the package name for, may be {@code null} + * @return the package name or an empty string + */ + public static String getPackageName(String className) { + if (StringUtils.isEmpty(className)) { + return StringUtils.EMPTY; + } + + // Strip array encoding + while (className.charAt(0) == '[') { + className = className.substring(1); + } + // Strip Object type encoding + if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { + className = className.substring(1); + } + + final int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + if (i == -1) { + return StringUtils.EMPTY; + } + return className.substring(0, i); + } + + // Abbreviated name + // ---------------------------------------------------------------------- + /** + *

              Gets the abbreviated name of a {@code Class}.

              + * + * @param cls the class to get the abbreviated name for, may be {@code null} + * @param len the desired length of the abbreviated name + * @return the abbreviated name or an empty string + * @throws IllegalArgumentException if len <= 0 + * @see #getAbbreviatedName(String, int) + * @since 3.4 + */ + public static String getAbbreviatedName(final Class cls, final int len) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getAbbreviatedName(cls.getName(), len); + } + + /** + *

              Gets the abbreviated class name from a {@code String}.

              + * + *

              The string passed in is assumed to be a class name - it is not checked.

              + * + *

              The abbreviation algorithm will shorten the class name, usually without + * significant loss of meaning.

              + *

              The abbreviated class name will always include the complete package hierarchy. + * If enough space is available, rightmost sub-packages will be displayed in full + * length.

              + * + *

              The following table illustrates the algorithm:

              + * + * + * + * + * + * + *
              classNamelenreturn
              null 1""
              "java.lang.String" 5"j.l.String"
              "java.lang.String"15"j.lang.String"
              "java.lang.String"30"java.lang.String"
              + * @param className the className to get the abbreviated name for, may be {@code null} + * @param len the desired length of the abbreviated name + * @return the abbreviated name or an empty string + * @throws IllegalArgumentException if len <= 0 + * @since 3.4 + */ + public static String getAbbreviatedName(final String className, final int len) { + if (len <= 0) { + throw new IllegalArgumentException("len must be > 0"); + } + if (className == null) { + return StringUtils.EMPTY; + } + + int availableSpace = len; + final int packageLevels = StringUtils.countMatches(className, '.'); + final String[] output = new String[packageLevels + 1]; + int endIndex = className.length() - 1; + for (int level = packageLevels; level >= 0; level--) { + final int startIndex = className.lastIndexOf('.', endIndex); + final String part = className.substring(startIndex + 1, endIndex + 1); + availableSpace -= part.length(); + if (level > 0) { + // all elements except top level require an additional char space + availableSpace--; + } + if (level == packageLevels) { + // ClassName is always complete + output[level] = part; + } else { + if (availableSpace > 0) { + output[level] = part; + } else { + // if no space is left still the first char is used + output[level] = part.substring(0, 1); + } + } + endIndex = startIndex - 1; + } + + return StringUtils.join(output, '.'); + } + + // Superclasses/Superinterfaces + // ---------------------------------------------------------------------- + /** + *

              Gets a {@code List} of superclasses for the given class.

              + * + * @param cls the class to look up, may be {@code null} + * @return the {@code List} of superclasses in order going up from this one + * {@code null} if null input + */ + public static List> getAllSuperclasses(final Class cls) { + if (cls == null) { + return null; + } + final List> classes = new ArrayList<>(); + Class superclass = cls.getSuperclass(); + while (superclass != null) { + classes.add(superclass); + superclass = superclass.getSuperclass(); + } + return classes; + } + + /** + *

              Gets a {@code List} of all interfaces implemented by the given + * class and its superclasses.

              + * + *

              The order is determined by looking through each interface in turn as + * declared in the source file and following its hierarchy up. Then each + * superclass is considered in the same way. Later duplicates are ignored, + * so the order is maintained.

              + * + * @param cls the class to look up, may be {@code null} + * @return the {@code List} of interfaces in order, + * {@code null} if null input + */ + public static List> getAllInterfaces(final Class cls) { + if (cls == null) { + return null; + } + + final LinkedHashSet> interfacesFound = new LinkedHashSet<>(); + getAllInterfaces(cls, interfacesFound); + + return new ArrayList<>(interfacesFound); + } + + /** + * Get the interfaces for the specified class. + * + * @param cls the class to look up, may be {@code null} + * @param interfacesFound the {@code Set} of interfaces for the class + */ + private static void getAllInterfaces(Class cls, final HashSet> interfacesFound) { + while (cls != null) { + final Class[] interfaces = cls.getInterfaces(); + + for (final Class i : interfaces) { + if (interfacesFound.add(i)) { + getAllInterfaces(i, interfacesFound); + } + } + + cls = cls.getSuperclass(); + } + } + + // Convert list + // ---------------------------------------------------------------------- + /** + *

              Given a {@code List} of class names, this method converts them into classes.

              + * + *

              A new {@code List} is returned. If the class name cannot be found, {@code null} + * is stored in the {@code List}. If the class name in the {@code List} is + * {@code null}, {@code null} is stored in the output {@code List}.

              + * + * @param classNames the classNames to change + * @return a {@code List} of Class objects corresponding to the class names, + * {@code null} if null input + * @throws ClassCastException if classNames contains a non String entry + */ + public static List> convertClassNamesToClasses(final List classNames) { + if (classNames == null) { + return null; + } + final List> classes = new ArrayList<>(classNames.size()); + for (final String className : classNames) { + try { + classes.add(Class.forName(className)); + } catch (final Exception ex) { + classes.add(null); + } + } + return classes; + } + + /** + *

              Given a {@code List} of {@code Class} objects, this method converts + * them into class names.

              + * + *

              A new {@code List} is returned. {@code null} objects will be copied into + * the returned list as {@code null}.

              + * + * @param classes the classes to change + * @return a {@code List} of class names corresponding to the Class objects, + * {@code null} if null input + * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry + */ + public static List convertClassesToClassNames(final List> classes) { + if (classes == null) { + return null; + } + final List classNames = new ArrayList<>(classes.size()); + for (final Class cls : classes) { + if (cls == null) { + classNames.add(null); + } else { + classNames.add(cls.getName()); + } + } + return classNames; + } + + // Is assignable + // ---------------------------------------------------------------------- + /** + *

              Checks if an array of Classes can be assigned to another array of Classes.

              + * + *

              This method calls {@link #isAssignable(Class, Class) isAssignable} for each + * Class pair in the input arrays. It can be used to check if a set of arguments + * (the first parameter) are suitably compatible with a set of method parameter types + * (the second parameter).

              + * + *

              Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this + * method takes into account widenings of primitive classes and + * {@code null}s.

              + * + *

              Primitive widenings allow an int to be assigned to a {@code long}, + * {@code float} or {@code double}. This method returns the correct + * result for these cases.

              + * + *

              {@code Null} may be assigned to any reference type. This method will + * return {@code true} if {@code null} is passed in and the toClass is + * non-primitive.

              + * + *

              Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.

              + * + *

              Since Lang 3.0, this method will default behavior for + * calculating assignability between primitive and wrapper types corresponding + * to the running Java version; i.e. autoboxing will be the default + * behavior in VMs running Java versions > 1.5.

              + * + * @param classArray the array of Classes to check, may be {@code null} + * @param toClassArray the array of Classes to try to assign into, may be {@code null} + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(final Class[] classArray, final Class... toClassArray) { + return isAssignable(classArray, toClassArray, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5)); + } + + /** + *

              Checks if an array of Classes can be assigned to another array of Classes.

              + * + *

              This method calls {@link #isAssignable(Class, Class) isAssignable} for each + * Class pair in the input arrays. It can be used to check if a set of arguments + * (the first parameter) are suitably compatible with a set of method parameter types + * (the second parameter).

              + * + *

              Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this + * method takes into account widenings of primitive classes and + * {@code null}s.

              + * + *

              Primitive widenings allow an int to be assigned to a {@code long}, + * {@code float} or {@code double}. This method returns the correct + * result for these cases.

              + * + *

              {@code Null} may be assigned to any reference type. This method will + * return {@code true} if {@code null} is passed in and the toClass is + * non-primitive.

              + * + *

              Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.

              + * + * @param classArray the array of Classes to check, may be {@code null} + * @param toClassArray the array of Classes to try to assign into, may be {@code null} + * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(Class[] classArray, Class[] toClassArray, final boolean autoboxing) { + if (ArrayUtils.isSameLength(classArray, toClassArray) == false) { + return false; + } + if (classArray == null) { + classArray = ArrayUtils.EMPTY_CLASS_ARRAY; + } + if (toClassArray == null) { + toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY; + } + for (int i = 0; i < classArray.length; i++) { + if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) { + return false; + } + } + return true; + } + + /** + * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, + * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * + * @param type + * The class to query or null. + * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, + * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * @since 3.1 + */ + public static boolean isPrimitiveOrWrapper(final Class type) { + if (type == null) { + return false; + } + return type.isPrimitive() || isPrimitiveWrapper(type); + } + + /** + * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short}, + * {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * + * @param type + * The class to query or null. + * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short}, + * {@link Integer}, {@link Long}, {@link Double}, {@link Float}). + * @since 3.1 + */ + public static boolean isPrimitiveWrapper(final Class type) { + return wrapperPrimitiveMap.containsKey(type); + } + + /** + *

              Checks if one {@code Class} can be assigned to a variable of + * another {@code Class}.

              + * + *

              Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, + * this method takes into account widenings of primitive classes and + * {@code null}s.

              + * + *

              Primitive widenings allow an int to be assigned to a long, float or + * double. This method returns the correct result for these cases.

              + * + *

              {@code Null} may be assigned to any reference type. This method + * will return {@code true} if {@code null} is passed in and the + * toClass is non-primitive.

              + * + *

              Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.

              + * + *

              Since Lang 3.0, this method will default behavior for + * calculating assignability between primitive and wrapper types corresponding + * to the running Java version; i.e. autoboxing will be the default + * behavior in VMs running Java versions > 1.5.

              + * + * @param cls the Class to check, may be null + * @param toClass the Class to try to assign into, returns false if null + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(final Class cls, final Class toClass) { + return isAssignable(cls, toClass, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5)); + } + + /** + *

              Checks if one {@code Class} can be assigned to a variable of + * another {@code Class}.

              + * + *

              Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, + * this method takes into account widenings of primitive classes and + * {@code null}s.

              + * + *

              Primitive widenings allow an int to be assigned to a long, float or + * double. This method returns the correct result for these cases.

              + * + *

              {@code Null} may be assigned to any reference type. This method + * will return {@code true} if {@code null} is passed in and the + * toClass is non-primitive.

              + * + *

              Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * widening primitive or widening reference conversion. See + * The Java Language Specification, + * sections 5.1.1, 5.1.2 and 5.1.4 for details.

              + * + * @param cls the Class to check, may be null + * @param toClass the Class to try to assign into, returns false if null + * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers + * @return {@code true} if assignment possible + */ + public static boolean isAssignable(Class cls, final Class toClass, final boolean autoboxing) { + if (toClass == null) { + return false; + } + // have to check for null, as isAssignableFrom doesn't + if (cls == null) { + return !toClass.isPrimitive(); + } + //autoboxing: + if (autoboxing) { + if (cls.isPrimitive() && !toClass.isPrimitive()) { + cls = primitiveToWrapper(cls); + if (cls == null) { + return false; + } + } + if (toClass.isPrimitive() && !cls.isPrimitive()) { + cls = wrapperToPrimitive(cls); + if (cls == null) { + return false; + } + } + } + if (cls.equals(toClass)) { + return true; + } + if (cls.isPrimitive()) { + if (toClass.isPrimitive() == false) { + return false; + } + if (Integer.TYPE.equals(cls)) { + return Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Long.TYPE.equals(cls)) { + return Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Boolean.TYPE.equals(cls)) { + return false; + } + if (Double.TYPE.equals(cls)) { + return false; + } + if (Float.TYPE.equals(cls)) { + return Double.TYPE.equals(toClass); + } + if (Character.TYPE.equals(cls)) { + return Integer.TYPE.equals(toClass) + || Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Short.TYPE.equals(cls)) { + return Integer.TYPE.equals(toClass) + || Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + if (Byte.TYPE.equals(cls)) { + return Short.TYPE.equals(toClass) + || Integer.TYPE.equals(toClass) + || Long.TYPE.equals(toClass) + || Float.TYPE.equals(toClass) + || Double.TYPE.equals(toClass); + } + // should never get here + return false; + } + return toClass.isAssignableFrom(cls); + } + + /** + *

              Converts the specified primitive Class object to its corresponding + * wrapper Class object.

              + * + *

              NOTE: From v2.2, this method handles {@code Void.TYPE}, + * returning {@code Void.TYPE}.

              + * + * @param cls the class to convert, may be null + * @return the wrapper class for {@code cls} or {@code cls} if + * {@code cls} is not a primitive. {@code null} if null input. + * @since 2.1 + */ + public static Class primitiveToWrapper(final Class cls) { + Class convertedClass = cls; + if (cls != null && cls.isPrimitive()) { + convertedClass = primitiveWrapperMap.get(cls); + } + return convertedClass; + } + + /** + *

              Converts the specified array of primitive Class objects to an array of + * its corresponding wrapper Class objects.

              + * + * @param classes the class array to convert, may be null or empty + * @return an array which contains for each given class, the wrapper class or + * the original class if class is not a primitive. {@code null} if null input. + * Empty array if an empty array passed in. + * @since 2.1 + */ + public static Class[] primitivesToWrappers(final Class... classes) { + if (classes == null) { + return null; + } + + if (classes.length == 0) { + return classes; + } + + final Class[] convertedClasses = new Class[classes.length]; + for (int i = 0; i < classes.length; i++) { + convertedClasses[i] = primitiveToWrapper(classes[i]); + } + return convertedClasses; + } + + /** + *

              Converts the specified wrapper class to its corresponding primitive + * class.

              + * + *

              This method is the counter part of {@code primitiveToWrapper()}. + * If the passed in class is a wrapper class for a primitive type, this + * primitive type will be returned (e.g. {@code Integer.TYPE} for + * {@code Integer.class}). For other classes, or if the parameter is + * null, the return value is null.

              + * + * @param cls the class to convert, may be null + * @return the corresponding primitive type if {@code cls} is a + * wrapper class, null otherwise + * @see #primitiveToWrapper(Class) + * @since 2.4 + */ + public static Class wrapperToPrimitive(final Class cls) { + return wrapperPrimitiveMap.get(cls); + } + + /** + *

              Converts the specified array of wrapper Class objects to an array of + * its corresponding primitive Class objects.

              + * + *

              This method invokes {@code wrapperToPrimitive()} for each element + * of the passed in array.

              + * + * @param classes the class array to convert, may be null or empty + * @return an array which contains for each given class, the primitive class or + * null if the original class is not a wrapper class. {@code null} if null input. + * Empty array if an empty array passed in. + * @see #wrapperToPrimitive(Class) + * @since 2.4 + */ + public static Class[] wrappersToPrimitives(final Class... classes) { + if (classes == null) { + return null; + } + + if (classes.length == 0) { + return classes; + } + + final Class[] convertedClasses = new Class[classes.length]; + for (int i = 0; i < classes.length; i++) { + convertedClasses[i] = wrapperToPrimitive(classes[i]); + } + return convertedClasses; + } + + // Inner class + // ---------------------------------------------------------------------- + /** + *

              Is the specified class an inner class or static nested class.

              + * + * @param cls the class to check, may be null + * @return {@code true} if the class is an inner or static nested class, + * false if not or {@code null} + */ + public static boolean isInnerClass(final Class cls) { + return cls != null && cls.getEnclosingClass() != null; + } + + // Class loading + // ---------------------------------------------------------------------- + /** + * Returns the class represented by {@code className} using the + * {@code classLoader}. This implementation supports the syntaxes + * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", + * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @param initialize whether the class must be initialized + * @return the class represented by {@code className} using the {@code classLoader} + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass( + final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException { + try { + Class clazz; + if (namePrimitiveMap.containsKey(className)) { + clazz = namePrimitiveMap.get(className); + } else { + clazz = Class.forName(toCanonicalName(className), initialize, classLoader); + } + return clazz; + } catch (final ClassNotFoundException ex) { + // allow path separators (.) as inner class name separators + final int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); + + if (lastDotIndex != -1) { + try { + return getClass(classLoader, className.substring(0, lastDotIndex) + + INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1), + initialize); + } catch (final ClassNotFoundException ex2) { // NOPMD + // ignore exception + } + } + + throw ex; + } + } + + /** + * Returns the (initialized) class represented by {@code className} + * using the {@code classLoader}. This implementation supports + * the syntaxes "{@code java.util.Map.Entry[]}", + * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", + * and "{@code [Ljava.util.Map$Entry;}". + * + * @param classLoader the class loader to use to load the class + * @param className the class name + * @return the class represented by {@code className} using the {@code classLoader} + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException { + return getClass(classLoader, className, true); + } + + /** + * Returns the (initialized) class represented by {@code className} + * using the current thread's context class loader. This implementation + * supports the syntaxes "{@code java.util.Map.Entry[]}", + * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", + * and "{@code [Ljava.util.Map$Entry;}". + * + * @param className the class name + * @return the class represented by {@code className} using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass(final String className) throws ClassNotFoundException { + return getClass(className, true); + } + + /** + * Returns the class represented by {@code className} using the + * current thread's context class loader. This implementation supports the + * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", + * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". + * + * @param className the class name + * @param initialize whether the class must be initialized + * @return the class represented by {@code className} using the current thread's context class loader + * @throws ClassNotFoundException if the class is not found + */ + public static Class getClass(final String className, final boolean initialize) throws ClassNotFoundException { + final ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); + final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL; + return getClass(loader, className, initialize); + } + + // Public method + // ---------------------------------------------------------------------- + /** + *

              Returns the desired Method much like {@code Class.getMethod}, however + * it ensures that the returned Method is from a public class or interface and not + * from an anonymous inner class. This means that the Method is invokable and + * doesn't fall foul of Java bug + * 4071957).

              + * + *
              +     *  Set set = Collections.unmodifiableSet(...);
              +     *  Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty",  new Class[0]);
              +     *  Object result = method.invoke(set, new Object[]);
              +     *  
              + * + * @param cls the class to check, not null + * @param methodName the name of the method + * @param parameterTypes the list of parameters + * @return the method + * @throws NullPointerException if the class is null + * @throws SecurityException if a security violation occurred + * @throws NoSuchMethodException if the method is not found in the given class + * or if the method doesn't conform with the requirements + */ + public static Method getPublicMethod(final Class cls, final String methodName, final Class... parameterTypes) + throws SecurityException, NoSuchMethodException { + + final Method declaredMethod = cls.getMethod(methodName, parameterTypes); + if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) { + return declaredMethod; + } + + final List> candidateClasses = new ArrayList<>(); + candidateClasses.addAll(getAllInterfaces(cls)); + candidateClasses.addAll(getAllSuperclasses(cls)); + + for (final Class candidateClass : candidateClasses) { + if (!Modifier.isPublic(candidateClass.getModifiers())) { + continue; + } + Method candidateMethod; + try { + candidateMethod = candidateClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException ex) { + continue; + } + if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) { + return candidateMethod; + } + } + + throw new NoSuchMethodException("Can't find a public method for " + + methodName + " " + ArrayUtils.toString(parameterTypes)); + } + + // ---------------------------------------------------------------------- + /** + * Converts a class name to a JLS style class name. + * + * @param className the class name + * @return the converted name + */ + private static String toCanonicalName(String className) { + className = StringUtils.deleteWhitespace(className); + if (className == null) { + throw new NullPointerException("className must not be null."); + } else if (className.endsWith("[]")) { + final StringBuilder classNameBuffer = new StringBuilder(); + while (className.endsWith("[]")) { + className = className.substring(0, className.length() - 2); + classNameBuffer.append("["); + } + final String abbreviation = abbreviationMap.get(className); + if (abbreviation != null) { + classNameBuffer.append(abbreviation); + } else { + classNameBuffer.append("L").append(className).append(";"); + } + className = classNameBuffer.toString(); + } + return className; + } + + /** + *

              Converts an array of {@code Object} in to an array of {@code Class} objects. + * If any of these objects is null, a null element will be inserted into the array.

              + * + *

              This method returns {@code null} for a {@code null} input array.

              + * + * @param array an {@code Object} array + * @return a {@code Class} array, {@code null} if null array input + * @since 2.4 + */ + public static Class[] toClass(final Object... array) { + if (array == null) { + return null; + } else if (array.length == 0) { + return ArrayUtils.EMPTY_CLASS_ARRAY; + } + final Class[] classes = new Class[array.length]; + for (int i = 0; i < array.length; i++) { + classes[i] = array[i] == null ? null : array[i].getClass(); + } + return classes; + } + + // Short canonical name + // ---------------------------------------------------------------------- + /** + *

              Gets the canonical name minus the package name for an {@code Object}.

              + * + * @param object the class to get the short name for, may be null + * @param valueIfNull the value to return if null + * @return the canonical name of the object without the package name, or the null value + * @since 2.4 + */ + public static String getShortCanonicalName(final Object object, final String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getShortCanonicalName(object.getClass().getName()); + } + + /** + *

              Gets the canonical name minus the package name from a {@code Class}.

              + * + * @param cls the class to get the short name for. + * @return the canonical name without the package name or an empty string + * @since 2.4 + */ + public static String getShortCanonicalName(final Class cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getShortCanonicalName(cls.getName()); + } + + /** + *

              Gets the canonical name minus the package name from a String.

              + * + *

              The string passed in is assumed to be a canonical name - it is not checked.

              + * + * @param canonicalName the class name to get the short name for + * @return the canonical name of the class without the package name or an empty string + * @since 2.4 + */ + public static String getShortCanonicalName(final String canonicalName) { + return ClassUtils.getShortClassName(getCanonicalName(canonicalName)); + } + + // Package name + // ---------------------------------------------------------------------- + /** + *

              Gets the package name from the canonical name of an {@code Object}.

              + * + * @param object the class to get the package name for, may be null + * @param valueIfNull the value to return if null + * @return the package name of the object, or the null value + * @since 2.4 + */ + public static String getPackageCanonicalName(final Object object, final String valueIfNull) { + if (object == null) { + return valueIfNull; + } + return getPackageCanonicalName(object.getClass().getName()); + } + + /** + *

              Gets the package name from the canonical name of a {@code Class}.

              + * + * @param cls the class to get the package name for, may be {@code null}. + * @return the package name or an empty string + * @since 2.4 + */ + public static String getPackageCanonicalName(final Class cls) { + if (cls == null) { + return StringUtils.EMPTY; + } + return getPackageCanonicalName(cls.getName()); + } + + /** + *

              Gets the package name from the canonical name.

              + * + *

              The string passed in is assumed to be a canonical name - it is not checked.

              + *

              If the class is unpackaged, return an empty string.

              + * + * @param canonicalName the canonical name to get the package name for, may be {@code null} + * @return the package name or an empty string + * @since 2.4 + */ + public static String getPackageCanonicalName(final String canonicalName) { + return ClassUtils.getPackageName(getCanonicalName(canonicalName)); + } + + /** + *

              Converts a given name of class into canonical format. + * If name of class is not a name of array class it returns + * unchanged name.

              + *

              Example: + *

                + *
              • {@code getCanonicalName("[I") = "int[]"}
              • + *
              • {@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}
              • + *
              • {@code getCanonicalName("java.lang.String") = "java.lang.String"}
              • + *
              + *

              + * + * @param className the name of class + * @return canonical form of class name + * @since 2.4 + */ + private static String getCanonicalName(String className) { + className = StringUtils.deleteWhitespace(className); + if (className == null) { + return null; + } + int dim = 0; + while (className.startsWith("[")) { + dim++; + className = className.substring(1); + } + if (dim < 1) { + return className; + } + if (className.startsWith("L")) { + className = className.substring( + 1, + className.endsWith(";") + ? className.length() - 1 + : className.length()); + } else { + if (className.length() > 0) { + className = reverseAbbreviationMap.get(className.substring(0, 1)); + } + } + final StringBuilder canonicalClassNameBuffer = new StringBuilder(className); + for (int i = 0; i < dim; i++) { + canonicalClassNameBuffer.append("[]"); + } + return canonicalClassNameBuffer.toString(); + } + + /** + * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order, + * excluding interfaces. + * + * @param type the type to get the class hierarchy from + * @return Iterable an Iterable over the class hierarchy of the given class + * @since 3.2 + */ + public static Iterable> hierarchy(final Class type) { + return hierarchy(type, Interfaces.EXCLUDE); + } + + /** + * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order. + * + * @param type the type to get the class hierarchy from + * @param interfacesBehavior switch indicating whether to include or exclude interfaces + * @return Iterable an Iterable over the class hierarchy of the given class + * @since 3.2 + */ + public static Iterable> hierarchy(final Class type, final Interfaces interfacesBehavior) { + final Iterable> classes = new Iterable>() { + + @Override + public Iterator> iterator() { + final MutableObject> next = new MutableObject>(type); + return new Iterator>() { + + @Override + public boolean hasNext() { + return next.getValue() != null; + } + + @Override + public Class next() { + final Class result = next.getValue(); + next.setValue(result.getSuperclass()); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + }; + } + + }; + if (interfacesBehavior != Interfaces.INCLUDE) { + return classes; + } + return new Iterable>() { + + @Override + public Iterator> iterator() { + final Set> seenInterfaces = new HashSet<>(); + final Iterator> wrapped = classes.iterator(); + + return new Iterator>() { + Iterator> interfaces = Collections.> emptySet().iterator(); + + @Override + public boolean hasNext() { + return interfaces.hasNext() || wrapped.hasNext(); + } + + @Override + public Class next() { + if (interfaces.hasNext()) { + final Class nextInterface = interfaces.next(); + seenInterfaces.add(nextInterface); + return nextInterface; + } + final Class nextSuperclass = wrapped.next(); + final Set> currentInterfaces = new LinkedHashSet<>(); + walkInterfaces(currentInterfaces, nextSuperclass); + interfaces = currentInterfaces.iterator(); + return nextSuperclass; + } + + private void walkInterfaces(final Set> addTo, final Class c) { + for (final Class iface : c.getInterfaces()) { + if (!seenInterfaces.contains(iface)) { + addTo.add(iface); + } + walkInterfaces(addTo, iface); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + }; + } + }; + } + +} diff --git a/src/org/apache/commons/lang3/Conversion.java b/src/org/apache/commons/lang3/Conversion.java new file mode 100644 index 0000000..6d381c0 --- /dev/null +++ b/src/org/apache/commons/lang3/Conversion.java @@ -0,0 +1,1565 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.apache.commons.lang3; + +import java.util.UUID; + + +/** + *

              + * Static methods to convert a type into another, with endianness and bit ordering awareness. + *

              + *

              + * The methods names follow a naming rule:
              + * {@code [source endianness][source bit ordering]To[destination endianness][destination bit ordering]} + *

              + *

              + * Source/destination type fields is one of the following: + *

              + *
                + *
              • binary: an array of booleans
              • + *
              • byte or byteArray
              • + *
              • int or intArray
              • + *
              • long or longArray
              • + *
              • hex: a String containing hexadecimal digits (lowercase in destination)
              • + *
              • hexDigit: a Char containing a hexadecimal digit (lowercase in destination)
              • + *
              • uuid
              • + *
              + *

              + * Endianness field: little endian is the default, in this case the field is absent. In case of + * big endian, the field is "Be".
              Bit ordering: Lsb0 is the default, in this case the field + * is absent. In case of Msb0, the field is "Msb0". + *

              + *

              + * Example: intBeMsb0ToHex convert an int with big endian byte order and Msb0 bit order into its + * hexadecimal string representation + *

              + *

              + * Most of the methods provide only default encoding for destination, this limits the number of + * ways to do one thing. Unless you are dealing with data from/to outside of the JVM platform, + * you should not need to use "Be" and "Msb0" methods. + *

              + *

              + * Development status: work on going, only a part of the little endian, Lsb0 methods implemented + * so far. + *

              + * + * @since Lang 3.2 + */ + +public class Conversion { + + private static final boolean[] TTTT = new boolean[] { true, true, true, true }; + private static final boolean[] FTTT = new boolean[] { false, true, true, true }; + private static final boolean[] TFTT = new boolean[] { true, false, true, true }; + private static final boolean[] FFTT = new boolean[] { false, false, true, true }; + private static final boolean[] TTFT = new boolean[] { true, true, false, true }; + private static final boolean[] FTFT = new boolean[] { false, true, false, true }; + private static final boolean[] TFFT = new boolean[] { true, false, false, true }; + private static final boolean[] FFFT = new boolean[] { false, false, false, true }; + private static final boolean[] TTTF = new boolean[] { true, true, true, false }; + private static final boolean[] FTTF = new boolean[] { false, true, true, false }; + private static final boolean[] TFTF = new boolean[] { true, false, true, false }; + private static final boolean[] FFTF = new boolean[] { false, false, true, false }; + private static final boolean[] TTFF = new boolean[] { true, true, false, false }; + private static final boolean[] FTFF = new boolean[] { false, true, false, false }; + private static final boolean[] TFFF = new boolean[] { true, false, false, false }; + private static final boolean[] FFFF = new boolean[] { false, false, false, false }; + + /** + *

              + * Converts a hexadecimal digit into an int using the default (Lsb0) bit ordering. + *

              + *

              + * '1' is converted to 1 + *

              + * + * @param hexDigit the hexadecimal digit to convert + * @return an int equals to {@code hexDigit} + * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit + */ + public static int hexDigitToInt(final char hexDigit) { + final int digit = Character.digit(hexDigit, 16); + if (digit < 0) { + throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); + } + return digit; + } + + /** + *

              + * Converts a hexadecimal digit into an int using the Msb0 bit ordering. + *

              + *

              + * '1' is converted to 8 + *

              + * + * @param hexDigit the hexadecimal digit to convert + * @return an int equals to {@code hexDigit} + * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit + */ + public static int hexDigitMsb0ToInt(final char hexDigit) { + switch (hexDigit) { + case '0': + return 0x0; + case '1': + return 0x8; + case '2': + return 0x4; + case '3': + return 0xC; + case '4': + return 0x2; + case '5': + return 0xA; + case '6': + return 0x6; + case '7': + return 0xE; + case '8': + return 0x1; + case '9': + return 0x9; + case 'a':// fall through + case 'A': + return 0x5; + case 'b':// fall through + case 'B': + return 0xD; + case 'c':// fall through + case 'C': + return 0x3; + case 'd':// fall through + case 'D': + return 0xB; + case 'e':// fall through + case 'E': + return 0x7; + case 'f':// fall through + case 'F': + return 0xF; + default: + throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); + } + } + + /** + *

              + * Converts a hexadecimal digit into binary (represented as boolean array) using the default + * (Lsb0) bit ordering. + *

              + *

              + * '1' is converted as follow: (1, 0, 0, 0) + *

              + * + * @param hexDigit the hexadecimal digit to convert + * @return a boolean array with the binary representation of {@code hexDigit} + * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit + */ + public static boolean[] hexDigitToBinary(final char hexDigit) { + switch (hexDigit) { + case '0': + return FFFF.clone(); + case '1': + return TFFF.clone(); + case '2': + return FTFF.clone(); + case '3': + return TTFF.clone(); + case '4': + return FFTF.clone(); + case '5': + return TFTF.clone(); + case '6': + return FTTF.clone(); + case '7': + return TTTF.clone(); + case '8': + return FFFT.clone(); + case '9': + return TFFT.clone(); + case 'a':// fall through + case 'A': + return FTFT.clone(); + case 'b':// fall through + case 'B': + return TTFT.clone(); + case 'c':// fall through + case 'C': + return FFTT.clone(); + case 'd':// fall through + case 'D': + return TFTT.clone(); + case 'e':// fall through + case 'E': + return FTTT.clone(); + case 'f':// fall through + case 'F': + return TTTT.clone(); + default: + throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); + } + } + + /** + *

              + * Converts a hexadecimal digit into binary (represented as boolean array) using the Msb0 + * bit ordering. + *

              + *

              + * '1' is converted as follow: (0, 0, 0, 1) + *

              + * + * @param hexDigit the hexadecimal digit to convert + * @return a boolean array with the binary representation of {@code hexDigit} + * @throws IllegalArgumentException if {@code hexDigit} is not a hexadecimal digit + */ + public static boolean[] hexDigitMsb0ToBinary(final char hexDigit) { + switch (hexDigit) { + case '0': + return FFFF.clone(); + case '1': + return FFFT.clone(); + case '2': + return FFTF.clone(); + case '3': + return FFTT.clone(); + case '4': + return FTFF.clone(); + case '5': + return FTFT.clone(); + case '6': + return FTTF.clone(); + case '7': + return FTTT.clone(); + case '8': + return TFFF.clone(); + case '9': + return TFFT.clone(); + case 'a':// fall through + case 'A': + return TFTF.clone(); + case 'b':// fall through + case 'B': + return TFTT.clone(); + case 'c':// fall through + case 'C': + return TTFF.clone(); + case 'd':// fall through + case 'D': + return TTFT.clone(); + case 'e':// fall through + case 'E': + return TTTF.clone(); + case 'f':// fall through + case 'F': + return TTTT.clone(); + default: + throw new IllegalArgumentException("Cannot interpret '" + hexDigit + "' as a hexadecimal digit"); + } + } + + /** + *

              + * Converts binary (represented as boolean array) to a hexadecimal digit using the default + * (Lsb0) bit ordering. + *

              + *

              + * (1, 0, 0, 0) is converted as follow: '1' + *

              + * + * @param src the binary to convert + * @return a hexadecimal digit representing the selected bits + * @throws IllegalArgumentException if {@code src} is empty + * @throws NullPointerException if {@code src} is {@code null} + */ + public static char binaryToHexDigit(final boolean[] src) { + return binaryToHexDigit(src, 0); + } + + /** + *

              + * Converts binary (represented as boolean array) to a hexadecimal digit using the default + * (Lsb0) bit ordering. + *

              + *

              + * (1, 0, 0, 0) is converted as follow: '1' + *

              + * + * @param src the binary to convert + * @param srcPos the position of the lsb to start the conversion + * @return a hexadecimal digit representing the selected bits + * @throws IllegalArgumentException if {@code src} is empty + * @throws NullPointerException if {@code src} is {@code null} + */ + public static char binaryToHexDigit(final boolean[] src, final int srcPos) { + if (src.length == 0) { + throw new IllegalArgumentException("Cannot convert an empty array."); + } + if (src.length > srcPos + 3 && src[srcPos + 3]) { + if (src.length > srcPos + 2 && src[srcPos + 2]) { + if (src.length > srcPos + 1 && src[srcPos + 1]) { + return src[srcPos] ? 'f' : 'e'; + } + return src[srcPos] ? 'd' : 'c'; + } + if (src.length > srcPos + 1 && src[srcPos + 1]) { + return src[srcPos] ? 'b' : 'a'; + } + return src[srcPos] ? '9' : '8'; + } + if (src.length > srcPos + 2 && src[srcPos + 2]) { + if (src.length > srcPos + 1 && src[srcPos + 1]) { + return src[srcPos] ? '7' : '6'; + } + return src[srcPos] ? '5' : '4'; + } + if (src.length > srcPos + 1 && src[srcPos + 1]) { + return src[srcPos] ? '3' : '2'; + } + return src[srcPos] ? '1' : '0'; + } + + /** + *

              + * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit + * ordering. + *

              + *

              + * (1, 0, 0, 0) is converted as follow: '8' + *

              + * + * @param src the binary to convert + * @return a hexadecimal digit representing the selected bits + * @throws IllegalArgumentException if {@code src} is empty, {@code src.length < 4} or + * {@code src.length > 8} + * @throws NullPointerException if {@code src} is {@code null} + */ + public static char binaryToHexDigitMsb0_4bits(final boolean[] src) { + return binaryToHexDigitMsb0_4bits(src, 0); + } + + /** + *

              + * Converts binary (represented as boolean array) to a hexadecimal digit using the Msb0 bit + * ordering. + *

              + *

              + * (1, 0, 0, 0) is converted as follow: '8' (1,0,0,1,1,0,1,0) with srcPos = 3 is converted + * to 'D' + *

              + * + * @param src the binary to convert + * @param srcPos the position of the lsb to start the conversion + * @return a hexadecimal digit representing the selected bits + * @throws IllegalArgumentException if {@code src} is empty, {@code src.length > 8} or + * {@code src.length - srcPos < 4} + * @throws NullPointerException if {@code src} is {@code null} + */ + public static char binaryToHexDigitMsb0_4bits(final boolean[] src, final int srcPos) { + if (src.length > 8) { + throw new IllegalArgumentException("src.length>8: src.length=" + src.length); + } + if (src.length - srcPos < 4) { + throw new IllegalArgumentException("src.length-srcPos<4: src.length=" + src.length + ", srcPos=" + srcPos); + } + if (src[srcPos + 3]) { + if (src[srcPos + 2]) { + if (src[srcPos + 1]) { + return src[srcPos] ? 'f' : '7'; + } + return src[srcPos] ? 'b' : '3'; + } + if (src[srcPos + 1]) { + return src[srcPos] ? 'd' : '5'; + } + return src[srcPos] ? '9' : '1'; + } + if (src[srcPos + 2]) { + if (src[srcPos + 1]) { + return src[srcPos] ? 'e' : '6'; + } + return src[srcPos] ? 'a' : '2'; + } + if (src[srcPos + 1]) { + return src[srcPos] ? 'c' : '4'; + } + return src[srcPos] ? '8' : '0'; + } + + /** + *

              + * Converts the first 4 bits of a binary (represented as boolean array) in big endian Msb0 + * bit ordering to a hexadecimal digit. + *

              + *

              + * (1, 0, 0, 0) is converted as follow: '8' (1,0,0,0,0,0,0,0, 0,0,0,0,0,1,0,0) is converted + * to '4' + *

              + * + * @param src the binary to convert + * @return a hexadecimal digit representing the selected bits + * @throws IllegalArgumentException if {@code src} is empty + * @throws NullPointerException if {@code src} is {@code null} + */ + public static char binaryBeMsb0ToHexDigit(final boolean[] src) { + return binaryBeMsb0ToHexDigit(src, 0); + } + + /** + *

              + * Converts a binary (represented as boolean array) in big endian Msb0 bit ordering to a + * hexadecimal digit. + *

              + *

              + * (1, 0, 0, 0) with srcPos = 0 is converted as follow: '8' (1,0,0,0,0,0,0,0, + * 0,0,0,1,0,1,0,0) with srcPos = 2 is converted to '5' + *

              + * + * @param src the binary to convert + * @param srcPos the position of the lsb to start the conversion + * @return a hexadecimal digit representing the selected bits + * @throws IllegalArgumentException if {@code src} is empty + * @throws NullPointerException if {@code src} is {@code null} + */ + public static char binaryBeMsb0ToHexDigit(boolean[] src, int srcPos) { + if (src.length == 0) { + throw new IllegalArgumentException("Cannot convert an empty array."); + } + final int beSrcPos = src.length - 1 - srcPos; + final int srcLen = Math.min(4, beSrcPos + 1); + final boolean[] paddedSrc = new boolean[4]; + System.arraycopy(src, beSrcPos + 1 - srcLen, paddedSrc, 4 - srcLen, srcLen); + src = paddedSrc; + srcPos = 0; + if (src[srcPos]) { + if (src.length > srcPos + 1 && src[srcPos + 1]) { + if (src.length > srcPos + 2 && src[srcPos + 2]) { + return src.length > srcPos + 3 && src[srcPos + 3] ? 'f' : 'e'; + } + return src.length > srcPos + 3 && src[srcPos + 3] ? 'd' : 'c'; + } + if (src.length > srcPos + 2 && src[srcPos + 2]) { + return src.length > srcPos + 3 && src[srcPos + 3] ? 'b' : 'a'; + } + return src.length > srcPos + 3 && src[srcPos + 3] ? '9' : '8'; + } + if (src.length > srcPos + 1 && src[srcPos + 1]) { + if (src.length > srcPos + 2 && src[srcPos + 2]) { + return src.length > srcPos + 3 && src[srcPos + 3] ? '7' : '6'; + } + return src.length > srcPos + 3 && src[srcPos + 3] ? '5' : '4'; + } + if (src.length > srcPos + 2 && src[srcPos + 2]) { + return src.length > srcPos + 3 && src[srcPos + 3] ? '3' : '2'; + } + return src.length > srcPos + 3 && src[srcPos + 3] ? '1' : '0'; + } + + /** + *

              + * Converts the 4 lsb of an int to a hexadecimal digit. + *

              + *

              + * 0 returns '0' + *

              + *

              + * 1 returns '1' + *

              + *

              + * 10 returns 'A' and so on... + *

              + * + * @param nibble the 4 bits to convert + * @return a hexadecimal digit representing the 4 lsb of {@code nibble} + * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15} + */ + public static char intToHexDigit(final int nibble) { + final char c = Character.forDigit(nibble, 16); + if (c == Character.MIN_VALUE) { + throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble); + } + return c; + } + + /** + *

              + * Converts the 4 lsb of an int to a hexadecimal digit encoded using the Msb0 bit ordering. + *

              + *

              + * 0 returns '0' + *

              + *

              + * 1 returns '8' + *

              + *

              + * 10 returns '5' and so on... + *

              + * + * @param nibble the 4 bits to convert + * @return a hexadecimal digit representing the 4 lsb of {@code nibble} + * @throws IllegalArgumentException if {@code nibble < 0} or {@code nibble > 15} + */ + public static char intToHexDigitMsb0(final int nibble) { + switch (nibble) { + case 0x0: + return '0'; + case 0x1: + return '8'; + case 0x2: + return '4'; + case 0x3: + return 'c'; + case 0x4: + return '2'; + case 0x5: + return 'a'; + case 0x6: + return '6'; + case 0x7: + return 'e'; + case 0x8: + return '1'; + case 0x9: + return '9'; + case 0xA: + return '5'; + case 0xB: + return 'd'; + case 0xC: + return '3'; + case 0xD: + return 'b'; + case 0xE: + return '7'; + case 0xF: + return 'f'; + default: + throw new IllegalArgumentException("nibble value not between 0 and 15: " + nibble); + } + } + + /** + *

              + * Converts an array of int into a long using the default (little endian, Lsb0) byte and bit + * ordering. + *

              + * + * @param src the int array to convert + * @param srcPos the position in {@code src}, in int unit, from where to start the + * conversion + * @param dstInit initial value of the destination long + * @param dstPos the position of the lsb, in bits, in the result long + * @param nInts the number of ints to convert + * @return a long containing the selected bits + * @throws IllegalArgumentException if {@code (nInts-1)*32+dstPos >= 64} + * @throws NullPointerException if {@code src} is {@code null} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nInts > src.length} + */ + public static long intArrayToLong(final int[] src, final int srcPos, final long dstInit, final int dstPos, + final int nInts) { + if (src.length == 0 && srcPos == 0 || 0 == nInts) { + return dstInit; + } + if ((nInts - 1) * 32 + dstPos >= 64) { + throw new IllegalArgumentException("(nInts-1)*32+dstPos is greater or equal to than 64"); + } + long out = dstInit; + for (int i = 0; i < nInts; i++) { + final int shift = i * 32 + dstPos; + final long bits = (0xffffffffL & src[i + srcPos]) << shift; + final long mask = 0xffffffffL << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts an array of short into a long using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the short array to convert + * @param srcPos the position in {@code src}, in short unit, from where to start the + * conversion + * @param dstInit initial value of the destination long + * @param dstPos the position of the lsb, in bits, in the result long + * @param nShorts the number of shorts to convert + * @return a long containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 64} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length} + */ + public static long shortArrayToLong(final short[] src, final int srcPos, final long dstInit, final int dstPos, + final int nShorts) { + if (src.length == 0 && srcPos == 0 || 0 == nShorts) { + return dstInit; + } + if ((nShorts - 1) * 16 + dstPos >= 64) { + throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 64"); + } + long out = dstInit; + for (int i = 0; i < nShorts; i++) { + final int shift = i * 16 + dstPos; + final long bits = (0xffffL & src[i + srcPos]) << shift; + final long mask = 0xffffL << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts an array of short into an int using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the short array to convert + * @param srcPos the position in {@code src}, in short unit, from where to start the + * conversion + * @param dstInit initial value of the destination int + * @param dstPos the position of the lsb, in bits, in the result int + * @param nShorts the number of shorts to convert + * @return an int containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code (nShorts-1)*16+dstPos >= 32} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nShorts > src.length} + */ + public static int shortArrayToInt(final short[] src, final int srcPos, final int dstInit, final int dstPos, + final int nShorts) { + if (src.length == 0 && srcPos == 0 || 0 == nShorts) { + return dstInit; + } + if ((nShorts - 1) * 16 + dstPos >= 32) { + throw new IllegalArgumentException("(nShorts-1)*16+dstPos is greater or equal to than 32"); + } + int out = dstInit; + for (int i = 0; i < nShorts; i++) { + final int shift = i * 16 + dstPos; + final int bits = (0xffff & src[i + srcPos]) << shift; + final int mask = 0xffff << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts an array of byte into a long using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the byte array to convert + * @param srcPos the position in {@code src}, in byte unit, from where to start the + * conversion + * @param dstInit initial value of the destination long + * @param dstPos the position of the lsb, in bits, in the result long + * @param nBytes the number of bytes to convert + * @return a long containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 64} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length} + */ + public static long byteArrayToLong(final byte[] src, final int srcPos, final long dstInit, final int dstPos, + final int nBytes) { + if (src.length == 0 && srcPos == 0 || 0 == nBytes) { + return dstInit; + } + if ((nBytes - 1) * 8 + dstPos >= 64) { + throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 64"); + } + long out = dstInit; + for (int i = 0; i < nBytes; i++) { + final int shift = i * 8 + dstPos; + final long bits = (0xffL & src[i + srcPos]) << shift; + final long mask = 0xffL << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts an array of byte into an int using the default (little endian, Lsb0) byte and bit + * ordering. + *

              + * + * @param src the byte array to convert + * @param srcPos the position in {@code src}, in byte unit, from where to start the + * conversion + * @param dstInit initial value of the destination int + * @param dstPos the position of the lsb, in bits, in the result int + * @param nBytes the number of bytes to convert + * @return an int containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 32} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length} + */ + public static int byteArrayToInt(final byte[] src, final int srcPos, final int dstInit, final int dstPos, + final int nBytes) { + if (src.length == 0 && srcPos == 0 || 0 == nBytes) { + return dstInit; + } + if ((nBytes - 1) * 8 + dstPos >= 32) { + throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 32"); + } + int out = dstInit; + for (int i = 0; i < nBytes; i++) { + final int shift = i * 8 + dstPos; + final int bits = (0xff & src[i + srcPos]) << shift; + final int mask = 0xff << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts an array of byte into a short using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the byte array to convert + * @param srcPos the position in {@code src}, in byte unit, from where to start the + * conversion + * @param dstInit initial value of the destination short + * @param dstPos the position of the lsb, in bits, in the result short + * @param nBytes the number of bytes to convert + * @return a short containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code (nBytes-1)*8+dstPos >= 16} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBytes > src.length} + */ + public static short byteArrayToShort(final byte[] src, final int srcPos, final short dstInit, final int dstPos, + final int nBytes) { + if (src.length == 0 && srcPos == 0 || 0 == nBytes) { + return dstInit; + } + if ((nBytes - 1) * 8 + dstPos >= 16) { + throw new IllegalArgumentException("(nBytes-1)*8+dstPos is greater or equal to than 16"); + } + short out = dstInit; + for (int i = 0; i < nBytes; i++) { + final int shift = i * 8 + dstPos; + final int bits = (0xff & src[i + srcPos]) << shift; + final int mask = 0xff << shift; + out = (short) ((out & ~mask) | bits); + } + return out; + } + + /** + *

              + * Converts an array of Char into a long using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the hex string to convert + * @param srcPos the position in {@code src}, in Char unit, from where to start the + * conversion + * @param dstInit initial value of the destination long + * @param dstPos the position of the lsb, in bits, in the result long + * @param nHex the number of Chars to convert + * @return a long containing the selected bits + * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 64} + */ + public static long hexToLong(final String src, final int srcPos, final long dstInit, final int dstPos, + final int nHex) { + if (0 == nHex) { + return dstInit; + } + if ((nHex - 1) * 4 + dstPos >= 64) { + throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 64"); + } + long out = dstInit; + for (int i = 0; i < nHex; i++) { + final int shift = i * 4 + dstPos; + final long bits = (0xfL & hexDigitToInt(src.charAt(i + srcPos))) << shift; + final long mask = 0xfL << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts an array of Char into an int using the default (little endian, Lsb0) byte and bit + * ordering. + *

              + * + * @param src the hex string to convert + * @param srcPos the position in {@code src}, in Char unit, from where to start the + * conversion + * @param dstInit initial value of the destination int + * @param dstPos the position of the lsb, in bits, in the result int + * @param nHex the number of Chars to convert + * @return an int containing the selected bits + * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 32} + */ + public static int hexToInt(final String src, final int srcPos, final int dstInit, final int dstPos, final int nHex) { + if (0 == nHex) { + return dstInit; + } + if ((nHex - 1) * 4 + dstPos >= 32) { + throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 32"); + } + int out = dstInit; + for (int i = 0; i < nHex; i++) { + final int shift = i * 4 + dstPos; + final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift; + final int mask = 0xf << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts an array of Char into a short using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the hex string to convert + * @param srcPos the position in {@code src}, in Char unit, from where to start the + * conversion + * @param dstInit initial value of the destination short + * @param dstPos the position of the lsb, in bits, in the result short + * @param nHex the number of Chars to convert + * @return a short containing the selected bits + * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 16} + */ + public static short hexToShort(final String src, final int srcPos, final short dstInit, final int dstPos, + final int nHex) { + if (0 == nHex) { + return dstInit; + } + if ((nHex - 1) * 4 + dstPos >= 16) { + throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 16"); + } + short out = dstInit; + for (int i = 0; i < nHex; i++) { + final int shift = i * 4 + dstPos; + final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift; + final int mask = 0xf << shift; + out = (short) ((out & ~mask) | bits); + } + return out; + } + + /** + *

              + * Converts an array of Char into a byte using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the hex string to convert + * @param srcPos the position in {@code src}, in Char unit, from where to start the + * conversion + * @param dstInit initial value of the destination byte + * @param dstPos the position of the lsb, in bits, in the result byte + * @param nHex the number of Chars to convert + * @return a byte containing the selected bits + * @throws IllegalArgumentException if {@code (nHexs-1)*4+dstPos >= 8} + */ + public static byte hexToByte(final String src, final int srcPos, final byte dstInit, final int dstPos, + final int nHex) { + if (0 == nHex) { + return dstInit; + } + if ((nHex - 1) * 4 + dstPos >= 8) { + throw new IllegalArgumentException("(nHexs-1)*4+dstPos is greater or equal to than 8"); + } + byte out = dstInit; + for (int i = 0; i < nHex; i++) { + final int shift = i * 4 + dstPos; + final int bits = (0xf & hexDigitToInt(src.charAt(i + srcPos))) << shift; + final int mask = 0xf << shift; + out = (byte) ((out & ~mask) | bits); + } + return out; + } + + /** + *

              + * Converts binary (represented as boolean array) into a long using the default (little + * endian, Lsb0) byte and bit ordering. + *

              + * + * @param src the binary to convert + * @param srcPos the position in {@code src}, in boolean unit, from where to start the + * conversion + * @param dstInit initial value of the destination long + * @param dstPos the position of the lsb, in bits, in the result long + * @param nBools the number of booleans to convert + * @return a long containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 64} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length} + */ + public static long binaryToLong(final boolean[] src, final int srcPos, final long dstInit, final int dstPos, + final int nBools) { + if (src.length == 0 && srcPos == 0 || 0 == nBools) { + return dstInit; + } + if (nBools - 1 + dstPos >= 64) { + throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 64"); + } + long out = dstInit; + for (int i = 0; i < nBools; i++) { + final int shift = i + dstPos; + final long bits = (src[i + srcPos] ? 1L : 0) << shift; + final long mask = 0x1L << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts binary (represented as boolean array) into an int using the default (little + * endian, Lsb0) byte and bit ordering. + *

              + * + * @param src the binary to convert + * @param srcPos the position in {@code src}, in boolean unit, from where to start the + * conversion + * @param dstInit initial value of the destination int + * @param dstPos the position of the lsb, in bits, in the result int + * @param nBools the number of booleans to convert + * @return an int containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 32} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length} + */ + public static int binaryToInt(final boolean[] src, final int srcPos, final int dstInit, final int dstPos, + final int nBools) { + if (src.length == 0 && srcPos == 0 || 0 == nBools) { + return dstInit; + } + if (nBools - 1 + dstPos >= 32) { + throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 32"); + } + int out = dstInit; + for (int i = 0; i < nBools; i++) { + final int shift = i + dstPos; + final int bits = (src[i + srcPos] ? 1 : 0) << shift; + final int mask = 0x1 << shift; + out = (out & ~mask) | bits; + } + return out; + } + + /** + *

              + * Converts binary (represented as boolean array) into a short using the default (little + * endian, Lsb0) byte and bit ordering. + *

              + * + * @param src the binary to convert + * @param srcPos the position in {@code src}, in boolean unit, from where to start the + * conversion + * @param dstInit initial value of the destination short + * @param dstPos the position of the lsb, in bits, in the result short + * @param nBools the number of booleans to convert + * @return a short containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 16} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length} + */ + public static short binaryToShort(final boolean[] src, final int srcPos, final short dstInit, final int dstPos, + final int nBools) { + if (src.length == 0 && srcPos == 0 || 0 == nBools) { + return dstInit; + } + if (nBools - 1 + dstPos >= 16) { + throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 16"); + } + short out = dstInit; + for (int i = 0; i < nBools; i++) { + final int shift = i + dstPos; + final int bits = (src[i + srcPos] ? 1 : 0) << shift; + final int mask = 0x1 << shift; + out = (short) ((out & ~mask) | bits); + } + return out; + } + + /** + *

              + * Converts binary (represented as boolean array) into a byte using the default (little + * endian, Lsb0) byte and bit ordering. + *

              + * + * @param src the binary to convert + * @param srcPos the position in {@code src}, in boolean unit, from where to start the + * conversion + * @param dstInit initial value of the destination byte + * @param dstPos the position of the lsb, in bits, in the result byte + * @param nBools the number of booleans to convert + * @return a byte containing the selected bits + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+dstPos >= 8} + * @throws ArrayIndexOutOfBoundsException if {@code srcPos + nBools > src.length} + */ + public static byte binaryToByte(final boolean[] src, final int srcPos, final byte dstInit, final int dstPos, + final int nBools) { + if (src.length == 0 && srcPos == 0 || 0 == nBools) { + return dstInit; + } + if (nBools - 1 + dstPos >= 8) { + throw new IllegalArgumentException("nBools-1+dstPos is greater or equal to than 8"); + } + byte out = dstInit; + for (int i = 0; i < nBools; i++) { + final int shift = i + dstPos; + final int bits = (src[i + srcPos] ? 1 : 0) << shift; + final int mask = 0x1 << shift; + out = (byte) ((out & ~mask) | bits); + } + return out; + } + + /** + *

              + * Converts a long into an array of int using the default (little endian, Lsb0) byte and bit + * ordering. + *

              + * + * @param src the long to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nInts the number of ints to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} and {@code nInts > 0} + * @throws IllegalArgumentException if {@code (nInts-1)*32+srcPos >= 64} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nInts > dst.length} + */ + public static int[] longToIntArray(final long src, final int srcPos, final int[] dst, final int dstPos, + final int nInts) { + if (0 == nInts) { + return dst; + } + if ((nInts - 1) * 32 + srcPos >= 64) { + throw new IllegalArgumentException("(nInts-1)*32+srcPos is greater or equal to than 64"); + } + for (int i = 0; i < nInts; i++) { + final int shift = i * 32 + srcPos; + dst[dstPos + i] = (int) (0xffffffff & (src >> shift)); + } + return dst; + } + + /** + *

              + * Converts a long into an array of short using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the long to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to + * the width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 64} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length} + */ + public static short[] longToShortArray(final long src, final int srcPos, final short[] dst, final int dstPos, + final int nShorts) { + if (0 == nShorts) { + return dst; + } + if ((nShorts - 1) * 16 + srcPos >= 64) { + throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 64"); + } + for (int i = 0; i < nShorts; i++) { + final int shift = i * 16 + srcPos; + dst[dstPos + i] = (short) (0xffff & (src >> shift)); + } + return dst; + } + + /** + *

              + * Converts an int into an array of short using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the int to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nShorts the number of shorts to copy to {@code dst}, must be smaller or equal to + * the width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code (nShorts-1)*16+srcPos >= 32} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nShorts > dst.length} + */ + public static short[] intToShortArray(final int src, final int srcPos, final short[] dst, final int dstPos, + final int nShorts) { + if (0 == nShorts) { + return dst; + } + if ((nShorts - 1) * 16 + srcPos >= 32) { + throw new IllegalArgumentException("(nShorts-1)*16+srcPos is greater or equal to than 32"); + } + for (int i = 0; i < nShorts; i++) { + final int shift = i * 16 + srcPos; + dst[dstPos + i] = (short) (0xffff & (src >> shift)); + } + return dst; + } + + /** + *

              + * Converts a long into an array of byte using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the long to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 64} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length} + */ + public static byte[] longToByteArray(final long src, final int srcPos, final byte[] dst, final int dstPos, + final int nBytes) { + if (0 == nBytes) { + return dst; + } + if ((nBytes - 1) * 8 + srcPos >= 64) { + throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 64"); + } + for (int i = 0; i < nBytes; i++) { + final int shift = i * 8 + srcPos; + dst[dstPos + i] = (byte) (0xff & (src >> shift)); + } + return dst; + } + + /** + *

              + * Converts an int into an array of byte using the default (little endian, Lsb0) byte and bit + * ordering. + *

              + * + * @param src the int to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 32} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length} + */ + public static byte[] intToByteArray(final int src, final int srcPos, final byte[] dst, final int dstPos, + final int nBytes) { + if (0 == nBytes) { + return dst; + } + if ((nBytes - 1) * 8 + srcPos >= 32) { + throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 32"); + } + for (int i = 0; i < nBytes; i++) { + final int shift = i * 8 + srcPos; + dst[dstPos + i] = (byte) (0xff & (src >> shift)); + } + return dst; + } + + /** + *

              + * Converts a short into an array of byte using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the short to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code (nBytes-1)*8+srcPos >= 16} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length} + */ + public static byte[] shortToByteArray(final short src, final int srcPos, final byte[] dst, final int dstPos, + final int nBytes) { + if (0 == nBytes) { + return dst; + } + if ((nBytes - 1) * 8 + srcPos >= 16) { + throw new IllegalArgumentException("(nBytes-1)*8+srcPos is greater or equal to than 16"); + } + for (int i = 0; i < nBytes; i++) { + final int shift = i * 8 + srcPos; + dst[dstPos + i] = (byte) (0xff & (src >> shift)); + } + return dst; + } + + /** + *

              + * Converts a long into an array of Char using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the long to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dstInit the initial value for the result String + * @param dstPos the position in {@code dst} where to copy the result + * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 64} + * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} + */ + public static String longToHex(final long src, final int srcPos, final String dstInit, final int dstPos, + final int nHexs) { + if (0 == nHexs) { + return dstInit; + } + if ((nHexs - 1) * 4 + srcPos >= 64) { + throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 64"); + } + final StringBuilder sb = new StringBuilder(dstInit); + int append = sb.length(); + for (int i = 0; i < nHexs; i++) { + final int shift = i * 4 + srcPos; + final int bits = (int) (0xF & (src >> shift)); + if (dstPos + i == append) { + ++append; + sb.append(intToHexDigit(bits)); + } else { + sb.setCharAt(dstPos + i, intToHexDigit(bits)); + } + } + return sb.toString(); + } + + /** + *

              + * Converts an int into an array of Char using the default (little endian, Lsb0) byte and bit + * ordering. + *

              + * + * @param src the int to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dstInit the initial value for the result String + * @param dstPos the position in {@code dst} where to copy the result + * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 32} + * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} + */ + public static String intToHex(final int src, final int srcPos, final String dstInit, final int dstPos, + final int nHexs) { + if (0 == nHexs) { + return dstInit; + } + if ((nHexs - 1) * 4 + srcPos >= 32) { + throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 32"); + } + final StringBuilder sb = new StringBuilder(dstInit); + int append = sb.length(); + for (int i = 0; i < nHexs; i++) { + final int shift = i * 4 + srcPos; + final int bits = 0xF & (src >> shift); + if (dstPos + i == append) { + ++append; + sb.append(intToHexDigit(bits)); + } else { + sb.setCharAt(dstPos + i, intToHexDigit(bits)); + } + } + return sb.toString(); + } + + /** + *

              + * Converts a short into an array of Char using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the short to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dstInit the initial value for the result String + * @param dstPos the position in {@code dst} where to copy the result + * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 16} + * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} + */ + public static String shortToHex(final short src, final int srcPos, final String dstInit, final int dstPos, + final int nHexs) { + if (0 == nHexs) { + return dstInit; + } + if ((nHexs - 1) * 4 + srcPos >= 16) { + throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 16"); + } + final StringBuilder sb = new StringBuilder(dstInit); + int append = sb.length(); + for (int i = 0; i < nHexs; i++) { + final int shift = i * 4 + srcPos; + final int bits = 0xF & (src >> shift); + if (dstPos + i == append) { + ++append; + sb.append(intToHexDigit(bits)); + } else { + sb.setCharAt(dstPos + i, intToHexDigit(bits)); + } + } + return sb.toString(); + } + + /** + *

              + * Converts a byte into an array of Char using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the byte to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dstInit the initial value for the result String + * @param dstPos the position in {@code dst} where to copy the result + * @param nHexs the number of Chars to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws IllegalArgumentException if {@code (nHexs-1)*4+srcPos >= 8} + * @throws StringIndexOutOfBoundsException if {@code dst.init.length() < dstPos} + */ + public static String byteToHex(final byte src, final int srcPos, final String dstInit, final int dstPos, + final int nHexs) { + if (0 == nHexs) { + return dstInit; + } + if ((nHexs - 1) * 4 + srcPos >= 8) { + throw new IllegalArgumentException("(nHexs-1)*4+srcPos is greater or equal to than 8"); + } + final StringBuilder sb = new StringBuilder(dstInit); + int append = sb.length(); + for (int i = 0; i < nHexs; i++) { + final int shift = i * 4 + srcPos; + final int bits = 0xF & (src >> shift); + if (dstPos + i == append) { + ++append; + sb.append(intToHexDigit(bits)); + } else { + sb.setCharAt(dstPos + i, intToHexDigit(bits)); + } + } + return sb.toString(); + } + + /** + *

              + * Converts a long into an array of boolean using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the long to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to + * the width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 64} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length} + */ + public static boolean[] longToBinary(final long src, final int srcPos, final boolean[] dst, final int dstPos, + final int nBools) { + if (0 == nBools) { + return dst; + } + if (nBools - 1 + srcPos >= 64) { + throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 64"); + } + for (int i = 0; i < nBools; i++) { + final int shift = i + srcPos; + dst[dstPos + i] = (0x1 & (src >> shift)) != 0; + } + return dst; + } + + /** + *

              + * Converts an int into an array of boolean using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the int to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to + * the width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 32} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length} + */ + public static boolean[] intToBinary(final int src, final int srcPos, final boolean[] dst, final int dstPos, + final int nBools) { + if (0 == nBools) { + return dst; + } + if (nBools - 1 + srcPos >= 32) { + throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 32"); + } + for (int i = 0; i < nBools; i++) { + final int shift = i + srcPos; + dst[dstPos + i] = (0x1 & (src >> shift)) != 0; + } + return dst; + } + + /** + *

              + * Converts a short into an array of boolean using the default (little endian, Lsb0) byte + * and bit ordering. + *

              + * + * @param src the short to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to + * the width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 16} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length} + */ + public static boolean[] shortToBinary(final short src, final int srcPos, final boolean[] dst, final int dstPos, + final int nBools) { + if (0 == nBools) { + return dst; + } + if (nBools - 1 + srcPos >= 16) { + throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 16"); + } + assert (nBools - 1) < 16 - srcPos; + for (int i = 0; i < nBools; i++) { + final int shift = i + srcPos; + dst[dstPos + i] = (0x1 & (src >> shift)) != 0; + } + return dst; + } + + /** + *

              + * Converts a byte into an array of boolean using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the byte to convert + * @param srcPos the position in {@code src}, in bits, from where to start the conversion + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBools the number of booleans to copy to {@code dst}, must be smaller or equal to + * the width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code nBools-1+srcPos >= 8} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBools > dst.length} + */ + public static boolean[] byteToBinary(final byte src, final int srcPos, final boolean[] dst, final int dstPos, + final int nBools) { + if (0 == nBools) { + return dst; + } + if (nBools - 1 + srcPos >= 8) { + throw new IllegalArgumentException("nBools-1+srcPos is greater or equal to than 8"); + } + for (int i = 0; i < nBools; i++) { + final int shift = i + srcPos; + dst[dstPos + i] = (0x1 & (src >> shift)) != 0; + } + return dst; + } + + /** + *

              + * Converts UUID into an array of byte using the default (little endian, Lsb0) byte and bit + * ordering. + *

              + * + * @param src the UUID to convert + * @param dst the destination array + * @param dstPos the position in {@code dst} where to copy the result + * @param nBytes the number of bytes to copy to {@code dst}, must be smaller or equal to the + * width of the input (from srcPos to msb) + * @return {@code dst} + * @throws NullPointerException if {@code dst} is {@code null} + * @throws IllegalArgumentException if {@code nBytes > 16} + * @throws ArrayIndexOutOfBoundsException if {@code dstPos + nBytes > dst.length} + */ + public static byte[] uuidToByteArray(final UUID src, final byte[] dst, final int dstPos, final int nBytes) { + if (0 == nBytes) { + return dst; + } + if (nBytes > 16) { + throw new IllegalArgumentException("nBytes is greater than 16"); + } + longToByteArray(src.getMostSignificantBits(), 0, dst, dstPos, nBytes > 8 ? 8 : nBytes); + if (nBytes >= 8) { + longToByteArray(src.getLeastSignificantBits(), 0, dst, dstPos + 8, nBytes - 8); + } + return dst; + } + + /** + *

              + * Converts bytes from an array into a UUID using the default (little endian, Lsb0) byte and + * bit ordering. + *

              + * + * @param src the byte array to convert + * @param srcPos the position in {@code src} where to copy the result from + * @return a UUID + * @throws NullPointerException if {@code src} is {@code null} + * @throws IllegalArgumentException if array does not contain at least 16 bytes beginning + * with {@code srcPos} + */ + public static UUID byteArrayToUuid(final byte[] src, final int srcPos) { + if (src.length - srcPos < 16) { + throw new IllegalArgumentException("Need at least 16 bytes for UUID"); + } + return new UUID(byteArrayToLong(src, srcPos, 0, 0, 8), byteArrayToLong(src, srcPos + 8, 0, 0, 8)); + } +} diff --git a/src/org/apache/commons/lang3/EnumUtils.java b/src/org/apache/commons/lang3/EnumUtils.java new file mode 100644 index 0000000..d6bcdc0 --- /dev/null +++ b/src/org/apache/commons/lang3/EnumUtils.java @@ -0,0 +1,312 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + *

              Utility library to provide helper methods for Java enums.

              + * + *

              #ThreadSafe#

              + * + * @since 3.0 + */ +public class EnumUtils { + + private static final String NULL_ELEMENTS_NOT_PERMITTED = "null elements not permitted"; + private static final String CANNOT_STORE_S_S_VALUES_IN_S_BITS = "Cannot store %s %s values in %s bits"; + private static final String S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE = "%s does not seem to be an Enum type"; + private static final String ENUM_CLASS_MUST_BE_DEFINED = "EnumClass must be defined."; + + /** + * This constructor is public to permit tools that require a JavaBean + * instance to operate. + */ + public EnumUtils() { + } + + /** + *

              Gets the {@code Map} of enums by name.

              + * + *

              This method is useful when you need a map of enums by name.

              + * + * @param the type of the enumeration + * @param enumClass the class of the enum to query, not null + * @return the modifiable map of enum names to enums, never null + */ + public static > Map getEnumMap(final Class enumClass) { + final Map map = new LinkedHashMap<>(); + for (final E e: enumClass.getEnumConstants()) { + map.put(e.name(), e); + } + return map; + } + + /** + *

              Gets the {@code List} of enums.

              + * + *

              This method is useful when you need a list of enums rather than an array.

              + * + * @param the type of the enumeration + * @param enumClass the class of the enum to query, not null + * @return the modifiable list of enums, never null + */ + public static > List getEnumList(final Class enumClass) { + return new ArrayList<>(Arrays.asList(enumClass.getEnumConstants())); + } + + /** + *

              Checks if the specified name is a valid enum for the class.

              + * + *

              This method differs from {@link Enum#valueOf} in that checks if the name is + * a valid enum without needing to catch the exception.

              + * + * @param the type of the enumeration + * @param enumClass the class of the enum to query, not null + * @param enumName the enum name, null returns false + * @return true if the enum name is valid, otherwise false + */ + public static > boolean isValidEnum(final Class enumClass, final String enumName) { + if (enumName == null) { + return false; + } + try { + Enum.valueOf(enumClass, enumName); + return true; + } catch (final IllegalArgumentException ex) { + return false; + } + } + + /** + *

              Gets the enum for the class, returning {@code null} if not found.

              + * + *

              This method differs from {@link Enum#valueOf} in that it does not throw an exception + * for an invalid enum name.

              + * + * @param the type of the enumeration + * @param enumClass the class of the enum to query, not null + * @param enumName the enum name, null returns null + * @return the enum, null if not found + */ + public static > E getEnum(final Class enumClass, final String enumName) { + if (enumName == null) { + return null; + } + try { + return Enum.valueOf(enumClass, enumName); + } catch (final IllegalArgumentException ex) { + return null; + } + } + + /** + *

              Creates a long bit vector representation of the given subset of an Enum.

              + * + *

              This generates a value that is usable by {@link EnumUtils#processBitVector}.

              + * + *

              Do not use this method if you have more than 64 values in your Enum, as this + * would create a value greater than a long can hold.

              + * + * @param enumClass the class of the enum we are working with, not {@code null} + * @param values the values we want to convert, not {@code null}, neither containing {@code null} + * @param the type of the enumeration + * @return a long whose value provides a binary representation of the given set of enum values. + * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values, + * or if any {@code values} {@code null} + * @since 3.0.1 + * @see #generateBitVectors(Class, Iterable) + */ + public static > long generateBitVector(final Class enumClass, final Iterable values) { + checkBitVectorable(enumClass); + Validate.notNull(values); + long total = 0; + for (final E constant : values) { + Validate.isTrue(constant != null, NULL_ELEMENTS_NOT_PERMITTED); + total |= 1L << constant.ordinal(); + } + return total; + } + + /** + *

              Creates a bit vector representation of the given subset of an Enum using as many {@code long}s as needed.

              + * + *

              This generates a value that is usable by {@link EnumUtils#processBitVectors}.

              + * + *

              Use this method if you have more than 64 values in your Enum.

              + * + * @param enumClass the class of the enum we are working with, not {@code null} + * @param values the values we want to convert, not {@code null}, neither containing {@code null} + * @param the type of the enumeration + * @return a long[] whose values provide a binary representation of the given set of enum values + * with least significant digits rightmost. + * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class, or if any {@code values} {@code null} + * @since 3.2 + */ + public static > long[] generateBitVectors(final Class enumClass, final Iterable values) { + asEnum(enumClass); + Validate.notNull(values); + final EnumSet condensed = EnumSet.noneOf(enumClass); + for (final E constant : values) { + Validate.isTrue(constant != null, NULL_ELEMENTS_NOT_PERMITTED); + condensed.add(constant); + } + final long[] result = new long[(enumClass.getEnumConstants().length - 1) / Long.SIZE + 1]; + for (final E value : condensed) { + result[value.ordinal() / Long.SIZE] |= 1L << (value.ordinal() % Long.SIZE); + } + ArrayUtils.reverse(result); + return result; + } + + /** + *

              Creates a long bit vector representation of the given array of Enum values.

              + * + *

              This generates a value that is usable by {@link EnumUtils#processBitVector}.

              + * + *

              Do not use this method if you have more than 64 values in your Enum, as this + * would create a value greater than a long can hold.

              + * + * @param enumClass the class of the enum we are working with, not {@code null} + * @param values the values we want to convert, not {@code null} + * @param the type of the enumeration + * @return a long whose value provides a binary representation of the given set of enum values. + * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values + * @since 3.0.1 + * @see #generateBitVectors(Class, Iterable) + */ + @SafeVarargs + public static > long generateBitVector(final Class enumClass, final E... values) { + Validate.noNullElements(values); + return generateBitVector(enumClass, Arrays. asList(values)); + } + + /** + *

              Creates a bit vector representation of the given subset of an Enum using as many {@code long}s as needed.

              + * + *

              This generates a value that is usable by {@link EnumUtils#processBitVectors}.

              + * + *

              Use this method if you have more than 64 values in your Enum.

              + * + * @param enumClass the class of the enum we are working with, not {@code null} + * @param values the values we want to convert, not {@code null}, neither containing {@code null} + * @param the type of the enumeration + * @return a long[] whose values provide a binary representation of the given set of enum values + * with least significant digits rightmost. + * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class, or if any {@code values} {@code null} + * @since 3.2 + */ + @SafeVarargs + public static > long[] generateBitVectors(final Class enumClass, final E... values) { + asEnum(enumClass); + Validate.noNullElements(values); + final EnumSet condensed = EnumSet.noneOf(enumClass); + Collections.addAll(condensed, values); + final long[] result = new long[(enumClass.getEnumConstants().length - 1) / Long.SIZE + 1]; + for (final E value : condensed) { + result[value.ordinal() / Long.SIZE] |= 1L << (value.ordinal() % Long.SIZE); + } + ArrayUtils.reverse(result); + return result; + } + + /** + *

              Convert a long value created by {@link EnumUtils#generateBitVector} into the set of + * enum values that it represents.

              + * + *

              If you store this value, beware any changes to the enum that would affect ordinal values.

              + * @param enumClass the class of the enum we are working with, not {@code null} + * @param value the long value representation of a set of enum values + * @param the type of the enumeration + * @return a set of enum values + * @throws NullPointerException if {@code enumClass} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values + * @since 3.0.1 + */ + public static > EnumSet processBitVector(final Class enumClass, final long value) { + checkBitVectorable(enumClass).getEnumConstants(); + return processBitVectors(enumClass, value); + } + + /** + *

              Convert a {@code long[]} created by {@link EnumUtils#generateBitVectors} into the set of + * enum values that it represents.

              + * + *

              If you store this value, beware any changes to the enum that would affect ordinal values.

              + * @param enumClass the class of the enum we are working with, not {@code null} + * @param values the long[] bearing the representation of a set of enum values, least significant digits rightmost, not {@code null} + * @param the type of the enumeration + * @return a set of enum values + * @throws NullPointerException if {@code enumClass} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class + * @since 3.2 + */ + public static > EnumSet processBitVectors(final Class enumClass, final long... values) { + final EnumSet results = EnumSet.noneOf(asEnum(enumClass)); + final long[] lvalues = ArrayUtils.clone(Validate.notNull(values)); + ArrayUtils.reverse(lvalues); + for (final E constant : enumClass.getEnumConstants()) { + final int block = constant.ordinal() / Long.SIZE; + if (block < lvalues.length && (lvalues[block] & 1L << (constant.ordinal() % Long.SIZE)) != 0) { + results.add(constant); + } + } + return results; + } + + /** + * Validate that {@code enumClass} is compatible with representation in a {@code long}. + * @param the type of the enumeration + * @param enumClass to check + * @return {@code enumClass} + * @throws NullPointerException if {@code enumClass} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values + * @since 3.0.1 + */ + private static > Class checkBitVectorable(final Class enumClass) { + final E[] constants = asEnum(enumClass).getEnumConstants(); + Validate.isTrue(constants.length <= Long.SIZE, CANNOT_STORE_S_S_VALUES_IN_S_BITS, + Integer.valueOf(constants.length), enumClass.getSimpleName(), Integer.valueOf(Long.SIZE)); + + return enumClass; + } + + /** + * Validate {@code enumClass}. + * @param the type of the enumeration + * @param enumClass to check + * @return {@code enumClass} + * @throws NullPointerException if {@code enumClass} is {@code null} + * @throws IllegalArgumentException if {@code enumClass} is not an enum class + * @since 3.2 + */ + private static > Class asEnum(final Class enumClass) { + Validate.notNull(enumClass, ENUM_CLASS_MUST_BE_DEFINED); + Validate.isTrue(enumClass.isEnum(), S_DOES_NOT_SEEM_TO_BE_AN_ENUM_TYPE, enumClass); + return enumClass; + } +} diff --git a/src/org/apache/commons/lang3/JavaVersion.java b/src/org/apache/commons/lang3/JavaVersion.java new file mode 100644 index 0000000..8c992f2 --- /dev/null +++ b/src/org/apache/commons/lang3/JavaVersion.java @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import org.apache.commons.lang3.math.NumberUtils; + +/** + *

              An enum representing all the versions of the Java specification. + * This is intended to mirror available values from the + * java.specification.version System property.

              + * + * @since 3.0 + */ +public enum JavaVersion { + + /** + * The Java version reported by Android. This is not an official Java version number. + */ + JAVA_0_9(1.5f, "0.9"), + + /** + * Java 1.1. + */ + JAVA_1_1(1.1f, "1.1"), + + /** + * Java 1.2. + */ + JAVA_1_2(1.2f, "1.2"), + + /** + * Java 1.3. + */ + JAVA_1_3(1.3f, "1.3"), + + /** + * Java 1.4. + */ + JAVA_1_4(1.4f, "1.4"), + + /** + * Java 1.5. + */ + JAVA_1_5(1.5f, "1.5"), + + /** + * Java 1.6. + */ + JAVA_1_6(1.6f, "1.6"), + + /** + * Java 1.7. + */ + JAVA_1_7(1.7f, "1.7"), + + /** + * Java 1.8. + */ + JAVA_1_8(1.8f, "1.8"), + + /** + * Java 1.9. + * + * @deprecated As of release 3.5, replaced by {@link #JAVA_9} + */ + @Deprecated + JAVA_1_9(9.0f, "9"), + + /** + * Java 9 + */ + JAVA_9(9.0f, "9"), + + /** + * The most recent java version. Mainly introduced to avoid to break when a new version of Java is used. + */ + JAVA_RECENT(maxVersion(), Float.toString(maxVersion())); + + /** + * The float value. + */ + private final float value; + /** + * The standard name. + */ + private final String name; + + /** + * Constructor. + * + * @param value the float value + * @param name the standard name, not null + */ + JavaVersion(final float value, final String name) { + this.value = value; + this.name = name; + } + + //----------------------------------------------------------------------- + /** + *

              Whether this version of Java is at least the version of Java passed in.

              + * + *

              For example:
              + * {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}

              + * + * @param requiredVersion the version to check against, not null + * @return true if this version is equal to or greater than the specified version + */ + public boolean atLeast(final JavaVersion requiredVersion) { + return this.value >= requiredVersion.value; + } + + /** + * Transforms the given string with a Java version number to the + * corresponding constant of this enumeration class. This method is used + * internally. + * + * @param nom the Java version as string + * @return the corresponding enumeration constant or null if the + * version is unknown + */ + // helper for static importing + static JavaVersion getJavaVersion(final String nom) { + return get(nom); + } + + /** + * Transforms the given string with a Java version number to the + * corresponding constant of this enumeration class. This method is used + * internally. + * + * @param nom the Java version as string + * @return the corresponding enumeration constant or null if the + * version is unknown + */ + static JavaVersion get(final String nom) { + if ("0.9".equals(nom)) { + return JAVA_0_9; + } else if ("1.1".equals(nom)) { + return JAVA_1_1; + } else if ("1.2".equals(nom)) { + return JAVA_1_2; + } else if ("1.3".equals(nom)) { + return JAVA_1_3; + } else if ("1.4".equals(nom)) { + return JAVA_1_4; + } else if ("1.5".equals(nom)) { + return JAVA_1_5; + } else if ("1.6".equals(nom)) { + return JAVA_1_6; + } else if ("1.7".equals(nom)) { + return JAVA_1_7; + } else if ("1.8".equals(nom)) { + return JAVA_1_8; + } else if ("9".equals(nom)) { + return JAVA_9; + } + if (nom == null) { + return null; + } + final float v = toFloatVersion(nom); + if ((v - 1.) < 1.) { // then we need to check decimals > .9 + final int firstComma = Math.max(nom.indexOf('.'), nom.indexOf(',')); + final int end = Math.max(nom.length(), nom.indexOf(',', firstComma)); + if (Float.parseFloat(nom.substring(firstComma + 1, end)) > .9f) { + return JAVA_RECENT; + } + } + return null; + } + + //----------------------------------------------------------------------- + /** + *

              The string value is overridden to return the standard name.

              + * + *

              For example, "1.5".

              + * + * @return the name, not null + */ + @Override + public String toString() { + return name; + } + + /** + * Gets the Java Version from the system or 99.0 if the {@code java.specification.version} system property is not set. + * + * @return the value of {@code java.specification.version} system property or 99.0 if it is not set. + */ + private static float maxVersion() { + final float v = toFloatVersion(System.getProperty("java.specification.version", "99.0")); + if (v > 0) { + return v; + } + return 99f; + } + + /** + * Parses a float value from a String. + * + * @param value the String to parse. + * @return the float value represented by the string or -1 if the given String can not be parsed. + */ + private static float toFloatVersion(final String value) { + final int defaultReturnValue = -1; + if (value.contains(".")) { + final String[] toParse = value.split("\\."); + if (toParse.length >= 2) { + return NumberUtils.toFloat(toParse[0] + '.' + toParse[1], defaultReturnValue); + } + } else { + return NumberUtils.toFloat(value, defaultReturnValue); + } + return defaultReturnValue; + } +} diff --git a/src/org/apache/commons/lang3/LocaleUtils.java b/src/org/apache/commons/lang3/LocaleUtils.java new file mode 100644 index 0000000..f13b52f --- /dev/null +++ b/src/org/apache/commons/lang3/LocaleUtils.java @@ -0,0 +1,329 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + *

              Operations to assist when working with a {@link Locale}.

              + * + *

              This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

              + * + * @since 2.2 + */ +public class LocaleUtils { + + /** Concurrent map of language locales by country. */ + private static final ConcurrentMap> cLanguagesByCountry = + new ConcurrentHashMap<>(); + + /** Concurrent map of country locales by language. */ + private static final ConcurrentMap> cCountriesByLanguage = + new ConcurrentHashMap<>(); + + /** + *

              {@code LocaleUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code LocaleUtils.toLocale("en_GB");}.

              + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate.

              + */ + public LocaleUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

              Converts a String to a Locale.

              + * + *

              This method takes the string format of a locale and creates the + * locale object from it.

              + * + *
              +     *   LocaleUtils.toLocale("")           = new Locale("", "")
              +     *   LocaleUtils.toLocale("en")         = new Locale("en", "")
              +     *   LocaleUtils.toLocale("en_GB")      = new Locale("en", "GB")
              +     *   LocaleUtils.toLocale("en_001")     = new Locale("en", "001")
              +     *   LocaleUtils.toLocale("en_GB_xxx")  = new Locale("en", "GB", "xxx")   (#)
              +     * 
              + * + *

              (#) The behaviour of the JDK variant constructor changed between JDK1.3 and JDK1.4. + * In JDK1.3, the constructor upper cases the variant, in JDK1.4, it doesn't. + * Thus, the result from getVariant() may vary depending on your JDK.

              + * + *

              This method validates the input strictly. + * The language code must be lowercase. + * The country code must be uppercase. + * The separator must be an underscore. + * The length must be correct. + *

              + * + * @param str the locale String to convert, null returns null + * @return a Locale, null if null input + * @throws IllegalArgumentException if the string is an invalid format + * @see Locale#forLanguageTag(String) + */ + public static Locale toLocale(final String str) { + if (str == null) { + return null; + } + if (str.isEmpty()) { // LANG-941 - JDK 8 introduced an empty locale where all fields are blank + return new Locale(StringUtils.EMPTY, StringUtils.EMPTY); + } + if (str.contains("#")) { // LANG-879 - Cannot handle Java 7 script & extensions + throw new IllegalArgumentException("Invalid locale format: " + str); + } + final int len = str.length(); + if (len < 2) { + throw new IllegalArgumentException("Invalid locale format: " + str); + } + final char ch0 = str.charAt(0); + if (ch0 == '_') { + if (len < 3) { + throw new IllegalArgumentException("Invalid locale format: " + str); + } + final char ch1 = str.charAt(1); + final char ch2 = str.charAt(2); + if (!Character.isUpperCase(ch1) || !Character.isUpperCase(ch2)) { + throw new IllegalArgumentException("Invalid locale format: " + str); + } + if (len == 3) { + return new Locale(StringUtils.EMPTY, str.substring(1, 3)); + } + if (len < 5) { + throw new IllegalArgumentException("Invalid locale format: " + str); + } + if (str.charAt(3) != '_') { + throw new IllegalArgumentException("Invalid locale format: " + str); + } + return new Locale(StringUtils.EMPTY, str.substring(1, 3), str.substring(4)); + } + + final String[] split = str.split("_", -1); + final int occurrences = split.length -1; + switch (occurrences) { + case 0: + if (StringUtils.isAllLowerCase(str) && (len == 2 || len == 3)) { + return new Locale(str); + } + throw new IllegalArgumentException("Invalid locale format: " + str); + + case 1: + if (StringUtils.isAllLowerCase(split[0]) && + (split[0].length() == 2 || split[0].length() == 3) && + (split[1].length() == 2 && StringUtils.isAllUpperCase(split[1])) || + (split[1].length() == 3 && StringUtils.isNumeric(split[1]))) { + return new Locale(split[0], split[1]); + } + throw new IllegalArgumentException("Invalid locale format: " + str); + + case 2: + if (StringUtils.isAllLowerCase(split[0]) && + (split[0].length() == 2 || split[0].length() == 3) && + (split[1].length() == 0 || split[1].length() == 2 && StringUtils.isAllUpperCase(split[1])) && + split[2].length() > 0) { + return new Locale(split[0], split[1], split[2]); + } + + //$FALL-THROUGH$ + default: + throw new IllegalArgumentException("Invalid locale format: " + str); + } + } + + //----------------------------------------------------------------------- + /** + *

              Obtains the list of locales to search through when performing + * a locale search.

              + * + *
              +     * localeLookupList(Locale("fr","CA","xxx"))
              +     *   = [Locale("fr","CA","xxx"), Locale("fr","CA"), Locale("fr")]
              +     * 
              + * + * @param locale the locale to start from + * @return the unmodifiable list of Locale objects, 0 being locale, not null + */ + public static List localeLookupList(final Locale locale) { + return localeLookupList(locale, locale); + } + + //----------------------------------------------------------------------- + /** + *

              Obtains the list of locales to search through when performing + * a locale search.

              + * + *
              +     * localeLookupList(Locale("fr", "CA", "xxx"), Locale("en"))
              +     *   = [Locale("fr","CA","xxx"), Locale("fr","CA"), Locale("fr"), Locale("en"]
              +     * 
              + * + *

              The result list begins with the most specific locale, then the + * next more general and so on, finishing with the default locale. + * The list will never contain the same locale twice.

              + * + * @param locale the locale to start from, null returns empty list + * @param defaultLocale the default locale to use if no other is found + * @return the unmodifiable list of Locale objects, 0 being locale, not null + */ + public static List localeLookupList(final Locale locale, final Locale defaultLocale) { + final List list = new ArrayList<>(4); + if (locale != null) { + list.add(locale); + if (locale.getVariant().length() > 0) { + list.add(new Locale(locale.getLanguage(), locale.getCountry())); + } + if (locale.getCountry().length() > 0) { + list.add(new Locale(locale.getLanguage(), StringUtils.EMPTY)); + } + if (list.contains(defaultLocale) == false) { + list.add(defaultLocale); + } + } + return Collections.unmodifiableList(list); + } + + //----------------------------------------------------------------------- + /** + *

              Obtains an unmodifiable list of installed locales.

              + * + *

              This method is a wrapper around {@link Locale#getAvailableLocales()}. + * It is more efficient, as the JDK method must create a new array each + * time it is called.

              + * + * @return the unmodifiable list of available locales + */ + public static List availableLocaleList() { + return SyncAvoid.AVAILABLE_LOCALE_LIST; + } + + //----------------------------------------------------------------------- + /** + *

              Obtains an unmodifiable set of installed locales.

              + * + *

              This method is a wrapper around {@link Locale#getAvailableLocales()}. + * It is more efficient, as the JDK method must create a new array each + * time it is called.

              + * + * @return the unmodifiable set of available locales + */ + public static Set availableLocaleSet() { + return SyncAvoid.AVAILABLE_LOCALE_SET; + } + + //----------------------------------------------------------------------- + /** + *

              Checks if the locale specified is in the list of available locales.

              + * + * @param locale the Locale object to check if it is available + * @return true if the locale is a known locale + */ + public static boolean isAvailableLocale(final Locale locale) { + return availableLocaleList().contains(locale); + } + + //----------------------------------------------------------------------- + /** + *

              Obtains the list of languages supported for a given country.

              + * + *

              This method takes a country code and searches to find the + * languages available for that country. Variant locales are removed.

              + * + * @param countryCode the 2 letter country code, null returns empty + * @return an unmodifiable List of Locale objects, not null + */ + public static List languagesByCountry(final String countryCode) { + if (countryCode == null) { + return Collections.emptyList(); + } + List langs = cLanguagesByCountry.get(countryCode); + if (langs == null) { + langs = new ArrayList<>(); + final List locales = availableLocaleList(); + for (int i = 0; i < locales.size(); i++) { + final Locale locale = locales.get(i); + if (countryCode.equals(locale.getCountry()) && + locale.getVariant().isEmpty()) { + langs.add(locale); + } + } + langs = Collections.unmodifiableList(langs); + cLanguagesByCountry.putIfAbsent(countryCode, langs); + langs = cLanguagesByCountry.get(countryCode); + } + return langs; + } + + //----------------------------------------------------------------------- + /** + *

              Obtains the list of countries supported for a given language.

              + * + *

              This method takes a language code and searches to find the + * countries available for that language. Variant locales are removed.

              + * + * @param languageCode the 2 letter language code, null returns empty + * @return an unmodifiable List of Locale objects, not null + */ + public static List countriesByLanguage(final String languageCode) { + if (languageCode == null) { + return Collections.emptyList(); + } + List countries = cCountriesByLanguage.get(languageCode); + if (countries == null) { + countries = new ArrayList<>(); + final List locales = availableLocaleList(); + for (int i = 0; i < locales.size(); i++) { + final Locale locale = locales.get(i); + if (languageCode.equals(locale.getLanguage()) && + locale.getCountry().length() != 0 && + locale.getVariant().isEmpty()) { + countries.add(locale); + } + } + countries = Collections.unmodifiableList(countries); + cCountriesByLanguage.putIfAbsent(languageCode, countries); + countries = cCountriesByLanguage.get(languageCode); + } + return countries; + } + + //----------------------------------------------------------------------- + // class to avoid synchronization (Init on demand) + static class SyncAvoid { + /** Unmodifiable list of available locales. */ + private static final List AVAILABLE_LOCALE_LIST; + /** Unmodifiable set of available locales. */ + private static final Set AVAILABLE_LOCALE_SET; + + static { + final List list = new ArrayList<>(Arrays.asList(Locale.getAvailableLocales())); // extra safe + AVAILABLE_LOCALE_LIST = Collections.unmodifiableList(list); + AVAILABLE_LOCALE_SET = Collections.unmodifiableSet(new HashSet<>(list)); + } + } + +} diff --git a/src/org/apache/commons/lang3/NotImplementedException.java b/src/org/apache/commons/lang3/NotImplementedException.java new file mode 100644 index 0000000..82e3784 --- /dev/null +++ b/src/org/apache/commons/lang3/NotImplementedException.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +/** + *

              Thrown to indicate that a block of code has not been implemented. + * This exception supplements UnsupportedOperationException + * by providing a more semantically rich description of the problem.

              + * + *

              NotImplementedException represents the case where the + * author has yet to implement the logic at this point in the program. + * This can act as an exception based TODO tag.

              + * + *
              + * public void foo() {
              + *   try {
              + *     // do something that throws an Exception
              + *   } catch (Exception ex) {
              + *     // don't know what to do here yet
              + *     throw new NotImplementedException("TODO", ex);
              + *   }
              + * }
              + * 
              + * + * This class was originally added in Lang 2.0, but removed in 3.0. + * + * @since 3.2 + */ +public class NotImplementedException extends UnsupportedOperationException { + + private static final long serialVersionUID = 20131021L; + + private final String code; + + /** + * Constructs a NotImplementedException. + * + * @param message description of the exception + * @since 3.2 + */ + public NotImplementedException(final String message) { + this(message, (String) null); + } + + /** + * Constructs a NotImplementedException. + * + * @param cause cause of the exception + * @since 3.2 + */ + public NotImplementedException(final Throwable cause) { + this(cause, null); + } + + /** + * Constructs a NotImplementedException. + * + * @param message description of the exception + * @param cause cause of the exception + * @since 3.2 + */ + public NotImplementedException(final String message, final Throwable cause) { + this(message, cause, null); + } + + /** + * Constructs a NotImplementedException. + * + * @param message description of the exception + * @param code code indicating a resource for more information regarding the lack of implementation + * @since 3.2 + */ + public NotImplementedException(final String message, final String code) { + super(message); + this.code = code; + } + + /** + * Constructs a NotImplementedException. + * + * @param cause cause of the exception + * @param code code indicating a resource for more information regarding the lack of implementation + * @since 3.2 + */ + public NotImplementedException(final Throwable cause, final String code) { + super(cause); + this.code = code; + } + + /** + * Constructs a NotImplementedException. + * + * @param message description of the exception + * @param cause cause of the exception + * @param code code indicating a resource for more information regarding the lack of implementation + * @since 3.2 + */ + public NotImplementedException(final String message, final Throwable cause, final String code) { + super(message, cause); + this.code = code; + } + + /** + * Obtain the not implemented code. This is an unformatted piece of text intended to point to + * further information regarding the lack of implementation. It might, for example, be an issue + * tracker ID or a URL. + * + * @return a code indicating a resource for more information regarding the lack of implementation + */ + public String getCode() { + return this.code; + } +} diff --git a/src/org/apache/commons/lang3/ObjectUtils.java b/src/org/apache/commons/lang3/ObjectUtils.java new file mode 100644 index 0000000..2edd81f --- /dev/null +++ b/src/org/apache/commons/lang3/ObjectUtils.java @@ -0,0 +1,1025 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeSet; + +import org.apache.commons.lang3.exception.CloneFailedException; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.lang3.text.StrBuilder; + +/** + *

              Operations on {@code Object}.

              + * + *

              This class tries to handle {@code null} input gracefully. + * An exception will generally not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

              + * + *

              #ThreadSafe#

              + * @since 1.0 + */ +//@Immutable +@SuppressWarnings("deprecation") // deprecated class StrBuilder is imported +// because it is part of the signature of deprecated methods +public class ObjectUtils { + + /** + *

              Singleton used as a {@code null} placeholder where + * {@code null} has another meaning.

              + * + *

              For example, in a {@code HashMap} the + * {@link java.util.HashMap#get(java.lang.Object)} method returns + * {@code null} if the {@code Map} contains {@code null} or if there + * is no matching key. The {@code Null} placeholder can be used to + * distinguish between these two cases.

              + * + *

              Another example is {@code Hashtable}, where {@code null} + * cannot be stored.

              + * + *

              This instance is Serializable.

              + */ + public static final Null NULL = new Null(); + + /** + *

              {@code ObjectUtils} instances should NOT be constructed in + * standard programming. Instead, the static methods on the class should + * be used, such as {@code ObjectUtils.defaultIfNull("a","b");}.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public ObjectUtils() { + super(); + } + + // Defaulting + //----------------------------------------------------------------------- + /** + *

              Returns a default value if the object passed is {@code null}.

              + * + *
              +     * ObjectUtils.defaultIfNull(null, null)      = null
              +     * ObjectUtils.defaultIfNull(null, "")        = ""
              +     * ObjectUtils.defaultIfNull(null, "zz")      = "zz"
              +     * ObjectUtils.defaultIfNull("abc", *)        = "abc"
              +     * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
              +     * 
              + * + * @param the type of the object + * @param object the {@code Object} to test, may be {@code null} + * @param defaultValue the default value to return, may be {@code null} + * @return {@code object} if it is not {@code null}, defaultValue otherwise + */ + public static T defaultIfNull(final T object, final T defaultValue) { + return object != null ? object : defaultValue; + } + + /** + *

              Returns the first value in the array which is not {@code null}. + * If all the values are {@code null} or the array is {@code null} + * or empty then {@code null} is returned.

              + * + *
              +     * ObjectUtils.firstNonNull(null, null)      = null
              +     * ObjectUtils.firstNonNull(null, "")        = ""
              +     * ObjectUtils.firstNonNull(null, null, "")  = ""
              +     * ObjectUtils.firstNonNull(null, "zz")      = "zz"
              +     * ObjectUtils.firstNonNull("abc", *)        = "abc"
              +     * ObjectUtils.firstNonNull(null, "xyz", *)  = "xyz"
              +     * ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
              +     * ObjectUtils.firstNonNull()                = null
              +     * 
              + * + * @param the component type of the array + * @param values the values to test, may be {@code null} or empty + * @return the first value from {@code values} which is not {@code null}, + * or {@code null} if there are no non-null values + * @since 3.0 + */ + @SafeVarargs + public static T firstNonNull(final T... values) { + if (values != null) { + for (final T val : values) { + if (val != null) { + return val; + } + } + } + return null; + } + + /** + * Checks if any value in the given array is not {@code null}. + * + *

              + * If all the values are {@code null} or the array is {@code null} + * or empty then {@code false} is returned. Otherwise {@code true} is returned. + *

              + * + *
              +     * ObjectUtils.anyNotNull(*)                = true
              +     * ObjectUtils.anyNotNull(*, null)          = true
              +     * ObjectUtils.anyNotNull(null, *)          = true
              +     * ObjectUtils.anyNotNull(null, null, *, *) = true
              +     * ObjectUtils.anyNotNull(null)             = false
              +     * ObjectUtils.anyNotNull(null, null)       = false
              +     * 
              + * + * @param values the values to test, may be {@code null} or empty + * @return {@code true} if there is at least one non-null value in the array, + * {@code false} if all values in the array are {@code null}s. + * If the array is {@code null} or empty {@code false} is also returned. + * @since 3.5 + */ + public static boolean anyNotNull(final Object... values) { + return firstNonNull(values) != null; + } + + /** + * Checks if all values in the array are not {@code nulls}. + * + *

              + * If any value is {@code null} or the array is {@code null} then + * {@code false} is returned. If all elements in array are not + * {@code null} or the array is empty (contains no elements) {@code true} + * is returned. + *

              + * + *
              +     * ObjectUtils.allNotNull(*)             = true
              +     * ObjectUtils.allNotNull(*, *)          = true
              +     * ObjectUtils.allNotNull(null)          = false
              +     * ObjectUtils.allNotNull(null, null)    = false
              +     * ObjectUtils.allNotNull(null, *)       = false
              +     * ObjectUtils.allNotNull(*, null)       = false
              +     * ObjectUtils.allNotNull(*, *, null, *) = false
              +     * 
              + * + * @param values the values to test, may be {@code null} or empty + * @return {@code false} if there is at least one {@code null} value in the array or the array is {@code null}, + * {@code true} if all values in the array are not {@code null}s or array contains no elements. + * @since 3.5 + */ + public static boolean allNotNull(final Object... values) { + if (values == null) { + return false; + } + + for (final Object val : values) { + if (val == null) { + return false; + } + } + + return true; + } + + // Null-safe equals/hashCode + //----------------------------------------------------------------------- + /** + *

              Compares two objects for equality, where either one or both + * objects may be {@code null}.

              + * + *
              +     * ObjectUtils.equals(null, null)                  = true
              +     * ObjectUtils.equals(null, "")                    = false
              +     * ObjectUtils.equals("", null)                    = false
              +     * ObjectUtils.equals("", "")                      = true
              +     * ObjectUtils.equals(Boolean.TRUE, null)          = false
              +     * ObjectUtils.equals(Boolean.TRUE, "true")        = false
              +     * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE)  = true
              +     * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
              +     * 
              + * + * @param object1 the first object, may be {@code null} + * @param object2 the second object, may be {@code null} + * @return {@code true} if the values of both objects are the same + * @deprecated this method has been replaced by {@code java.util.Objects.equals(Object, Object)} in Java 7 and will + * be removed from future releases. + */ + @Deprecated + public static boolean equals(final Object object1, final Object object2) { + if (object1 == object2) { + return true; + } + if (object1 == null || object2 == null) { + return false; + } + return object1.equals(object2); + } + + /** + *

              Compares two objects for inequality, where either one or both + * objects may be {@code null}.

              + * + *
              +     * ObjectUtils.notEqual(null, null)                  = false
              +     * ObjectUtils.notEqual(null, "")                    = true
              +     * ObjectUtils.notEqual("", null)                    = true
              +     * ObjectUtils.notEqual("", "")                      = false
              +     * ObjectUtils.notEqual(Boolean.TRUE, null)          = true
              +     * ObjectUtils.notEqual(Boolean.TRUE, "true")        = true
              +     * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE)  = false
              +     * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
              +     * 
              + * + * @param object1 the first object, may be {@code null} + * @param object2 the second object, may be {@code null} + * @return {@code false} if the values of both objects are the same + */ + public static boolean notEqual(final Object object1, final Object object2) { + return ObjectUtils.equals(object1, object2) == false; + } + + /** + *

              Gets the hash code of an object returning zero when the + * object is {@code null}.

              + * + *
              +     * ObjectUtils.hashCode(null)   = 0
              +     * ObjectUtils.hashCode(obj)    = obj.hashCode()
              +     * 
              + * + * @param obj the object to obtain the hash code of, may be {@code null} + * @return the hash code of the object, or zero if null + * @since 2.1 + * @deprecated this method has been replaced by {@code java.util.Objects.hashCode(Object)} in Java 7 and will be + * removed in future releases + */ + @Deprecated + public static int hashCode(final Object obj) { + // hashCode(Object) retained for performance, as hash code is often critical + return obj == null ? 0 : obj.hashCode(); + } + + /** + *

              Gets the hash code for multiple objects.

              + * + *

              This allows a hash code to be rapidly calculated for a number of objects. + * The hash code for a single object is the not same as {@link #hashCode(Object)}. + * The hash code for multiple objects is the same as that calculated by an + * {@code ArrayList} containing the specified objects.

              + * + *
              +     * ObjectUtils.hashCodeMulti()                 = 1
              +     * ObjectUtils.hashCodeMulti((Object[]) null)  = 1
              +     * ObjectUtils.hashCodeMulti(a)                = 31 + a.hashCode()
              +     * ObjectUtils.hashCodeMulti(a,b)              = (31 + a.hashCode()) * 31 + b.hashCode()
              +     * ObjectUtils.hashCodeMulti(a,b,c)            = ((31 + a.hashCode()) * 31 + b.hashCode()) * 31 + c.hashCode()
              +     * 
              + * + * @param objects the objects to obtain the hash code of, may be {@code null} + * @return the hash code of the objects, or zero if null + * @since 3.0 + * @deprecated this method has been replaced by {@code java.util.Objects.hash(Object...)} in Java 7 and will be + * removed in future releases. + */ + @Deprecated + public static int hashCodeMulti(final Object... objects) { + int hash = 1; + if (objects != null) { + for (final Object object : objects) { + final int tmpHash = ObjectUtils.hashCode(object); + hash = hash * 31 + tmpHash; + } + } + return hash; + } + + // Identity ToString + //----------------------------------------------------------------------- + /** + *

              Gets the toString that would be produced by {@code Object} + * if a class did not override toString itself. {@code null} + * will return {@code null}.

              + * + *
              +     * ObjectUtils.identityToString(null)         = null
              +     * ObjectUtils.identityToString("")           = "java.lang.String@1e23"
              +     * ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
              +     * 
              + * + * @param object the object to create a toString for, may be + * {@code null} + * @return the default toString text, or {@code null} if + * {@code null} passed in + */ + public static String identityToString(final Object object) { + if (object == null) { + return null; + } + final StringBuilder builder = new StringBuilder(); + identityToString(builder, object); + return builder.toString(); + } + + /** + *

              Appends the toString that would be produced by {@code Object} + * if a class did not override toString itself. {@code null} + * will throw a NullPointerException for either of the two parameters.

              + * + *
              +     * ObjectUtils.identityToString(appendable, "")            = appendable.append("java.lang.String@1e23"
              +     * ObjectUtils.identityToString(appendable, Boolean.TRUE)  = appendable.append("java.lang.Boolean@7fa"
              +     * ObjectUtils.identityToString(appendable, Boolean.TRUE)  = appendable.append("java.lang.Boolean@7fa")
              +     * 
              + * + * @param appendable the appendable to append to + * @param object the object to create a toString for + * @throws IOException if an I/O error occurs + * @since 3.2 + */ + public static void identityToString(final Appendable appendable, final Object object) throws IOException { + if (object == null) { + throw new NullPointerException("Cannot get the toString of a null identity"); + } + appendable.append(object.getClass().getName()) + .append('@') + .append(Integer.toHexString(System.identityHashCode(object))); + } + + /** + *

              Appends the toString that would be produced by {@code Object} + * if a class did not override toString itself. {@code null} + * will throw a NullPointerException for either of the two parameters.

              + * + *
              +     * ObjectUtils.identityToString(builder, "")            = builder.append("java.lang.String@1e23"
              +     * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa"
              +     * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa")
              +     * 
              + * + * @param builder the builder to append to + * @param object the object to create a toString for + * @since 3.2 + * @deprecated as of 3.6, use one of the other {@code identityToString} methods instead + */ + @Deprecated + public static void identityToString(final StrBuilder builder, final Object object) { + if (object == null) { + throw new NullPointerException("Cannot get the toString of a null identity"); + } + builder.append(object.getClass().getName()) + .append('@') + .append(Integer.toHexString(System.identityHashCode(object))); + } + + /** + *

              Appends the toString that would be produced by {@code Object} + * if a class did not override toString itself. {@code null} + * will throw a NullPointerException for either of the two parameters.

              + * + *
              +     * ObjectUtils.identityToString(buf, "")            = buf.append("java.lang.String@1e23"
              +     * ObjectUtils.identityToString(buf, Boolean.TRUE)  = buf.append("java.lang.Boolean@7fa"
              +     * ObjectUtils.identityToString(buf, Boolean.TRUE)  = buf.append("java.lang.Boolean@7fa")
              +     * 
              + * + * @param buffer the buffer to append to + * @param object the object to create a toString for + * @since 2.4 + */ + public static void identityToString(final StringBuffer buffer, final Object object) { + if (object == null) { + throw new NullPointerException("Cannot get the toString of a null identity"); + } + buffer.append(object.getClass().getName()) + .append('@') + .append(Integer.toHexString(System.identityHashCode(object))); + } + + /** + *

              Appends the toString that would be produced by {@code Object} + * if a class did not override toString itself. {@code null} + * will throw a NullPointerException for either of the two parameters.

              + * + *
              +     * ObjectUtils.identityToString(builder, "")            = builder.append("java.lang.String@1e23"
              +     * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa"
              +     * ObjectUtils.identityToString(builder, Boolean.TRUE)  = builder.append("java.lang.Boolean@7fa")
              +     * 
              + * + * @param builder the builder to append to + * @param object the object to create a toString for + * @since 3.2 + */ + public static void identityToString(final StringBuilder builder, final Object object) { + if (object == null) { + throw new NullPointerException("Cannot get the toString of a null identity"); + } + builder.append(object.getClass().getName()) + .append('@') + .append(Integer.toHexString(System.identityHashCode(object))); + } + + // ToString + //----------------------------------------------------------------------- + /** + *

              Gets the {@code toString} of an {@code Object} returning + * an empty string ("") if {@code null} input.

              + * + *
              +     * ObjectUtils.toString(null)         = ""
              +     * ObjectUtils.toString("")           = ""
              +     * ObjectUtils.toString("bat")        = "bat"
              +     * ObjectUtils.toString(Boolean.TRUE) = "true"
              +     * 
              + * + * @see StringUtils#defaultString(String) + * @see String#valueOf(Object) + * @param obj the Object to {@code toString}, may be null + * @return the passed in Object's toString, or {@code ""} if {@code null} input + * @since 2.0 + * @deprecated this method has been replaced by {@code java.util.Objects.toString(Object)} in Java 7 and will be + * removed in future releases. Note however that said method will return "null" for null references, while this + * method returns an empty String. To preserve behavior use {@code java.util.Objects.toString(myObject, "")} + */ + @Deprecated + public static String toString(final Object obj) { + return obj == null ? StringUtils.EMPTY : obj.toString(); + } + + /** + *

              Gets the {@code toString} of an {@code Object} returning + * a specified text if {@code null} input.

              + * + *
              +     * ObjectUtils.toString(null, null)           = null
              +     * ObjectUtils.toString(null, "null")         = "null"
              +     * ObjectUtils.toString("", "null")           = ""
              +     * ObjectUtils.toString("bat", "null")        = "bat"
              +     * ObjectUtils.toString(Boolean.TRUE, "null") = "true"
              +     * 
              + * + * @see StringUtils#defaultString(String,String) + * @see String#valueOf(Object) + * @param obj the Object to {@code toString}, may be null + * @param nullStr the String to return if {@code null} input, may be null + * @return the passed in Object's toString, or {@code nullStr} if {@code null} input + * @since 2.0 + * @deprecated this method has been replaced by {@code java.util.Objects.toString(Object, String)} in Java 7 and + * will be removed in future releases. + */ + @Deprecated + public static String toString(final Object obj, final String nullStr) { + return obj == null ? nullStr : obj.toString(); + } + + // Comparable + //----------------------------------------------------------------------- + /** + *

              Null safe comparison of Comparables.

              + * + * @param type of the values processed by this method + * @param values the set of comparable values, may be null + * @return + *
                + *
              • If any objects are non-null and unequal, the lesser object. + *
              • If all objects are non-null and equal, the first. + *
              • If any of the comparables are null, the lesser of the non-null objects. + *
              • If all the comparables are null, null is returned. + *
              + */ + @SafeVarargs + public static > T min(final T... values) { + T result = null; + if (values != null) { + for (final T value : values) { + if (compare(value, result, true) < 0) { + result = value; + } + } + } + return result; + } + + /** + *

              Null safe comparison of Comparables.

              + * + * @param type of the values processed by this method + * @param values the set of comparable values, may be null + * @return + *
                + *
              • If any objects are non-null and unequal, the greater object. + *
              • If all objects are non-null and equal, the first. + *
              • If any of the comparables are null, the greater of the non-null objects. + *
              • If all the comparables are null, null is returned. + *
              + */ + @SafeVarargs + public static > T max(final T... values) { + T result = null; + if (values != null) { + for (final T value : values) { + if (compare(value, result, false) > 0) { + result = value; + } + } + } + return result; + } + + /** + *

              Null safe comparison of Comparables. + * {@code null} is assumed to be less than a non-{@code null} value.

              + * + * @param type of the values processed by this method + * @param c1 the first comparable, may be null + * @param c2 the second comparable, may be null + * @return a negative value if c1 < c2, zero if c1 = c2 + * and a positive value if c1 > c2 + */ + public static > int compare(final T c1, final T c2) { + return compare(c1, c2, false); + } + + /** + *

              Null safe comparison of Comparables.

              + * + * @param type of the values processed by this method + * @param c1 the first comparable, may be null + * @param c2 the second comparable, may be null + * @param nullGreater if true {@code null} is considered greater + * than a non-{@code null} value or if false {@code null} is + * considered less than a Non-{@code null} value + * @return a negative value if c1 < c2, zero if c1 = c2 + * and a positive value if c1 > c2 + * @see java.util.Comparator#compare(Object, Object) + */ + public static > int compare(final T c1, final T c2, final boolean nullGreater) { + if (c1 == c2) { + return 0; + } else if (c1 == null) { + return nullGreater ? 1 : -1; + } else if (c2 == null) { + return nullGreater ? -1 : 1; + } + return c1.compareTo(c2); + } + + /** + * Find the "best guess" middle value among comparables. If there is an even + * number of total values, the lower of the two middle values will be returned. + * @param type of values processed by this method + * @param items to compare + * @return T at middle position + * @throws NullPointerException if items is {@code null} + * @throws IllegalArgumentException if items is empty or contains {@code null} values + * @since 3.0.1 + */ + @SafeVarargs + public static > T median(final T... items) { + Validate.notEmpty(items); + Validate.noNullElements(items); + final TreeSet sort = new TreeSet<>(); + Collections.addAll(sort, items); + @SuppressWarnings("unchecked") //we know all items added were T instances + final T result = (T) sort.toArray()[(sort.size() - 1) / 2]; + return result; + } + + /** + * Find the "best guess" middle value among comparables. If there is an even + * number of total values, the lower of the two middle values will be returned. + * @param type of values processed by this method + * @param comparator to use for comparisons + * @param items to compare + * @return T at middle position + * @throws NullPointerException if items or comparator is {@code null} + * @throws IllegalArgumentException if items is empty or contains {@code null} values + * @since 3.0.1 + */ + @SafeVarargs + public static T median(final Comparator comparator, final T... items) { + Validate.notEmpty(items, "null/empty items"); + Validate.noNullElements(items); + Validate.notNull(comparator, "null comparator"); + final TreeSet sort = new TreeSet<>(comparator); + Collections.addAll(sort, items); + @SuppressWarnings("unchecked") //we know all items added were T instances + final + T result = (T) sort.toArray()[(sort.size() - 1) / 2]; + return result; + } + + // Mode + //----------------------------------------------------------------------- + /** + * Find the most frequently occurring item. + * + * @param type of values processed by this method + * @param items to check + * @return most populous T, {@code null} if non-unique or no items supplied + * @since 3.0.1 + */ + @SafeVarargs + public static T mode(final T... items) { + if (ArrayUtils.isNotEmpty(items)) { + final HashMap occurrences = new HashMap<>(items.length); + for (final T t : items) { + final MutableInt count = occurrences.get(t); + if (count == null) { + occurrences.put(t, new MutableInt(1)); + } else { + count.increment(); + } + } + T result = null; + int max = 0; + for (final Map.Entry e : occurrences.entrySet()) { + final int cmp = e.getValue().intValue(); + if (cmp == max) { + result = null; + } else if (cmp > max) { + max = cmp; + result = e.getKey(); + } + } + return result; + } + return null; + } + + // cloning + //----------------------------------------------------------------------- + /** + *

              Clone an object.

              + * + * @param the type of the object + * @param obj the object to clone, null returns null + * @return the clone if the object implements {@link Cloneable} otherwise {@code null} + * @throws CloneFailedException if the object is cloneable and the clone operation fails + * @since 3.0 + */ + public static T clone(final T obj) { + if (obj instanceof Cloneable) { + final Object result; + if (obj.getClass().isArray()) { + final Class componentType = obj.getClass().getComponentType(); + if (!componentType.isPrimitive()) { + result = ((Object[]) obj).clone(); + } else { + int length = Array.getLength(obj); + result = Array.newInstance(componentType, length); + while (length-- > 0) { + Array.set(result, length, Array.get(obj, length)); + } + } + } else { + try { + final Method clone = obj.getClass().getMethod("clone"); + result = clone.invoke(obj); + } catch (final NoSuchMethodException e) { + throw new CloneFailedException("Cloneable type " + + obj.getClass().getName() + + " has no clone method", e); + } catch (final IllegalAccessException e) { + throw new CloneFailedException("Cannot clone Cloneable type " + + obj.getClass().getName(), e); + } catch (final InvocationTargetException e) { + throw new CloneFailedException("Exception cloning Cloneable type " + + obj.getClass().getName(), e.getCause()); + } + } + @SuppressWarnings("unchecked") // OK because input is of type T + final T checked = (T) result; + return checked; + } + + return null; + } + + /** + *

              Clone an object if possible.

              + * + *

              This method is similar to {@link #clone(Object)}, but will return the provided + * instance as the return value instead of {@code null} if the instance + * is not cloneable. This is more convenient if the caller uses different + * implementations (e.g. of a service) and some of the implementations do not allow concurrent + * processing or have state. In such cases the implementation can simply provide a proper + * clone implementation and the caller's code does not have to change.

              + * + * @param the type of the object + * @param obj the object to clone, null returns null + * @return the clone if the object implements {@link Cloneable} otherwise the object itself + * @throws CloneFailedException if the object is cloneable and the clone operation fails + * @since 3.0 + */ + public static T cloneIfPossible(final T obj) { + final T clone = clone(obj); + return clone == null ? obj : clone; + } + + // Null + //----------------------------------------------------------------------- + /** + *

              Class used as a null placeholder where {@code null} + * has another meaning.

              + * + *

              For example, in a {@code HashMap} the + * {@link java.util.HashMap#get(java.lang.Object)} method returns + * {@code null} if the {@code Map} contains {@code null} or if there is + * no matching key. The {@code Null} placeholder can be used to distinguish + * between these two cases.

              + * + *

              Another example is {@code Hashtable}, where {@code null} + * cannot be stored.

              + */ + public static class Null implements Serializable { + /** + * Required for serialization support. Declare serialization compatibility with Commons Lang 1.0 + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 7092611880189329093L; + + /** + * Restricted constructor - singleton. + */ + Null() { + super(); + } + + /** + *

              Ensure singleton.

              + * + * @return the singleton value + */ + private Object readResolve() { + return ObjectUtils.NULL; + } + } + + + // Constants (LANG-816): + /* + These methods ensure constants are not inlined by javac. + For example, typically a developer might declare a constant like so: + + public final static int MAGIC_NUMBER = 5; + + Should a different jar file refer to this, and the MAGIC_NUMBER + is changed a later date (e.g., MAGIC_NUMBER = 6), the different jar + file will need to recompile itself. This is because javac + typically inlines the primitive or String constant directly into + the bytecode, and removes the reference to the MAGIC_NUMBER field. + + To help the other jar (so that it does not need to recompile + when constants are changed) the original developer can declare + their constant using one of the CONST() utility methods, instead: + + public final static int MAGIC_NUMBER = CONST(5); + */ + + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static boolean MAGIC_FLAG = ObjectUtils.CONST(true);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the boolean value to return + * @return the boolean v, unchanged + * @since 3.2 + */ + public static boolean CONST(final boolean v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static byte MAGIC_BYTE = ObjectUtils.CONST((byte) 127);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the byte value to return + * @return the byte v, unchanged + * @since 3.2 + */ + public static byte CONST(final byte v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static byte MAGIC_BYTE = ObjectUtils.CONST_BYTE(127);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the byte literal (as an int) value to return + * @throws IllegalArgumentException if the value passed to v + * is larger than a byte, that is, smaller than -128 or + * larger than 127. + * @return the byte v, unchanged + * @since 3.2 + */ + public static byte CONST_BYTE(final int v) throws IllegalArgumentException { + if (v < Byte.MIN_VALUE || v > Byte.MAX_VALUE) { + throw new IllegalArgumentException("Supplied value must be a valid byte literal between -128 and 127: [" + v + "]"); + } + return (byte) v; + } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static char MAGIC_CHAR = ObjectUtils.CONST('a');
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the char value to return + * @return the char v, unchanged + * @since 3.2 + */ + public static char CONST(final char v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static short MAGIC_SHORT = ObjectUtils.CONST((short) 123);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the short value to return + * @return the short v, unchanged + * @since 3.2 + */ + public static short CONST(final short v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static short MAGIC_SHORT = ObjectUtils.CONST_SHORT(127);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the short literal (as an int) value to return + * @throws IllegalArgumentException if the value passed to v + * is larger than a short, that is, smaller than -32768 or + * larger than 32767. + * @return the byte v, unchanged + * @since 3.2 + */ + public static short CONST_SHORT(final int v) throws IllegalArgumentException { + if (v < Short.MIN_VALUE || v > Short.MAX_VALUE) { + throw new IllegalArgumentException("Supplied value must be a valid byte literal between -32768 and 32767: [" + v + "]"); + } + return (short) v; + } + + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static int MAGIC_INT = ObjectUtils.CONST(123);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the int value to return + * @return the int v, unchanged + * @since 3.2 + */ + public static int CONST(final int v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static long MAGIC_LONG = ObjectUtils.CONST(123L);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the long value to return + * @return the long v, unchanged + * @since 3.2 + */ + public static long CONST(final long v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static float MAGIC_FLOAT = ObjectUtils.CONST(1.0f);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the float value to return + * @return the float v, unchanged + * @since 3.2 + */ + public static float CONST(final float v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static double MAGIC_DOUBLE = ObjectUtils.CONST(1.0);
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param v the double value to return + * @return the double v, unchanged + * @since 3.2 + */ + public static double CONST(final double v) { return v; } + + /** + * This method returns the provided value unchanged. + * This can prevent javac from inlining a constant + * field, e.g., + * + *
              +     *     public final static String MAGIC_STRING = ObjectUtils.CONST("abc");
              +     * 
              + * + * This way any jars that refer to this field do not + * have to recompile themselves if the field's value + * changes at some future date. + * + * @param the Object type + * @param v the genericized Object value to return (typically a String). + * @return the genericized Object v, unchanged (typically a String). + * @since 3.2 + */ + public static T CONST(final T v) { return v; } + +} diff --git a/src/org/apache/commons/lang3/RandomStringUtils.java b/src/org/apache/commons/lang3/RandomStringUtils.java new file mode 100644 index 0000000..ec62d50 --- /dev/null +++ b/src/org/apache/commons/lang3/RandomStringUtils.java @@ -0,0 +1,466 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.util.Random; + +/** + *

              Operations for random {@code String}s.

              + *

              Currently private high surrogate characters are ignored. + * These are Unicode characters that fall between the values 56192 (db80) + * and 56319 (dbff) as we don't know how to handle them. + * High and low surrogates are correctly dealt with - that is if a + * high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f) + * then it is followed by a low surrogate. If a low surrogate is chosen, + * 56320 (dc00) to 57343 (dfff) then it is placed after a randomly + * chosen high surrogate.

              + * + *

              #ThreadSafe#

              + * @since 1.0 + */ +public class RandomStringUtils { + + /** + *

              Random object used by random method. This has to be not local + * to the random method so as to not return the same value in the + * same millisecond.

              + */ + private static final Random RANDOM = new Random(); + + /** + *

              {@code RandomStringUtils} instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * {@code RandomStringUtils.random(5);}.

              + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate.

              + */ + public RandomStringUtils() { + super(); + } + + // Random + //----------------------------------------------------------------------- + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of all characters.

              + * + * @param count the length of random string to create + * @return the random string + */ + public static String random(final int count) { + return random(count, false, false); + } + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of characters whose + * ASCII value is between {@code 32} and {@code 126} (inclusive).

              + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomAscii(final int count) { + return random(count, 32, 127, false, false); + } + + /** + *

              Creates a random string whose length is between the inclusive minimum and + * the exclusive maximum.

              + * + *

              Characters will be chosen from the set of characters whose + * ASCII value is between {@code 32} and {@code 126} (inclusive).

              + * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public static String randomAscii(final int minLengthInclusive, final int maxLengthExclusive) { + return randomAscii(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of Latin alphabetic + * characters (a-z, A-Z).

              + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomAlphabetic(final int count) { + return random(count, true, false); + } + + /** + *

              Creates a random string whose length is between the inclusive minimum and + * the exclusive maximum.

              + * + *

              Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z).

              + * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public static String randomAlphabetic(final int minLengthInclusive, final int maxLengthExclusive) { + return randomAlphabetic(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of Latin alphabetic + * characters (a-z, A-Z) and the digits 0-9.

              + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomAlphanumeric(final int count) { + return random(count, true, true); + } + + /** + *

              Creates a random string whose length is between the inclusive minimum and + * the exclusive maximum.

              + * + *

              Characters will be chosen from the set of Latin alphabetic + * characters (a-z, A-Z) and the digits 0-9.

              + * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public static String randomAlphanumeric(final int minLengthInclusive, final int maxLengthExclusive) { + return randomAlphanumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + *

              Creates a random string whose length is the number of characters specified.

              + * + *

              Characters will be chosen from the set of characters which match the POSIX [:graph:] + * regular expression character class. This class contains all visible ASCII characters + * (i.e. anything except spaces and control characters).

              + * + * @param count the length of random string to create + * @return the random string + * @since 3.5 + */ + public static String randomGraph(final int count) { + return random(count, 33, 126, false, false); + } + + /** + *

              Creates a random string whose length is between the inclusive minimum and + * the exclusive maximum.

              + * + *

              Characters will be chosen from the set of \p{Graph} characters.

              + * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public static String randomGraph(final int minLengthInclusive, final int maxLengthExclusive) { + return randomGraph(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of numeric + * characters.

              + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomNumeric(final int count) { + return random(count, false, true); + } + + /** + *

              Creates a random string whose length is between the inclusive minimum and + * the exclusive maximum.

              + * + *

              Characters will be chosen from the set of \p{Digit} characters.

              + * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public static String randomNumeric(final int minLengthInclusive, final int maxLengthExclusive) { + return randomNumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + *

              Creates a random string whose length is the number of characters specified.

              + * + *

              Characters will be chosen from the set of characters which match the POSIX [:print:] + * regular expression character class. This class includes all visible ASCII characters and spaces + * (i.e. anything except control characters).

              + * + * @param count the length of random string to create + * @return the random string + * @since 3.5 + */ + public static String randomPrint(final int count) { + return random(count, 32, 126, false, false); + } + + /** + *

              Creates a random string whose length is between the inclusive minimum and + * the exclusive maximum.

              + * + *

              Characters will be chosen from the set of \p{Print} characters.

              + * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public static String randomPrint(final int minLengthInclusive, final int maxLengthExclusive) { + return randomPrint(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of alpha-numeric + * characters as indicated by the arguments.

              + * + * @param count the length of random string to create + * @param letters if {@code true}, generated string may include + * alphabetic characters + * @param numbers if {@code true}, generated string may include + * numeric characters + * @return the random string + */ + public static String random(final int count, final boolean letters, final boolean numbers) { + return random(count, 0, 0, letters, numbers); + } + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of alpha-numeric + * characters as indicated by the arguments.

              + * + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters if {@code true}, generated string may include + * alphabetic characters + * @param numbers if {@code true}, generated string may include + * numeric characters + * @return the random string + */ + public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers) { + return random(count, start, end, letters, numbers, null, RANDOM); + } + + /** + *

              Creates a random string based on a variety of options, using + * default source of randomness.

              + * + *

              This method has exactly the same semantics as + * {@link #random(int,int,int,boolean,boolean,char[],Random)}, but + * instead of using an externally supplied source of randomness, it uses + * the internal static {@link Random} instance.

              + * + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters only allow letters? + * @param numbers only allow numbers? + * @param chars the set of chars to choose randoms from. + * If {@code null}, then it will use the set of all chars. + * @return the random string + * @throws ArrayIndexOutOfBoundsException if there are not + * {@code (end - start) + 1} characters in the set array. + */ + public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers, final char... chars) { + return random(count, start, end, letters, numbers, chars, RANDOM); + } + + /** + *

              Creates a random string based on a variety of options, using + * supplied source of randomness.

              + * + *

              If start and end are both {@code 0}, start and end are set + * to {@code ' '} and {@code 'z'}, the ASCII printable + * characters, will be used, unless letters and numbers are both + * {@code false}, in which case, start and end are set to + * {@code 0} and {@link Character#MAX_CODE_POINT}. + * + *

              If set is not {@code null}, characters between start and + * end are chosen.

              + * + *

              This method accepts a user-supplied {@link Random} + * instance to use as a source of randomness. By seeding a single + * {@link Random} instance with a fixed seed and using it for each call, + * the same random sequence of strings can be generated repeatedly + * and predictably.

              + * + * @param count the length of random string to create + * @param start the position in set of chars to start at (inclusive) + * @param end the position in set of chars to end before (exclusive) + * @param letters only allow letters? + * @param numbers only allow numbers? + * @param chars the set of chars to choose randoms from, must not be empty. + * If {@code null}, then it will use the set of all chars. + * @param random a source of randomness. + * @return the random string + * @throws ArrayIndexOutOfBoundsException if there are not + * {@code (end - start) + 1} characters in the set array. + * @throws IllegalArgumentException if {@code count} < 0 or the provided chars array is empty. + * @since 2.0 + */ + public static String random(int count, int start, int end, final boolean letters, final boolean numbers, + final char[] chars, final Random random) { + if (count == 0) { + return StringUtils.EMPTY; + } else if (count < 0) { + throw new IllegalArgumentException("Requested random string length " + count + " is less than 0."); + } + if (chars != null && chars.length == 0) { + throw new IllegalArgumentException("The chars array must not be empty"); + } + + if (start == 0 && end == 0) { + if (chars != null) { + end = chars.length; + } else { + if (!letters && !numbers) { + end = Character.MAX_CODE_POINT; + } else { + end = 'z' + 1; + start = ' '; + } + } + } else { + if (end <= start) { + throw new IllegalArgumentException("Parameter end (" + end + ") must be greater than start (" + start + ")"); + } + } + + final int zero_digit_ascii = 48; + final int first_letter_ascii = 65; + + if (chars == null) { + if (numbers && end <= zero_digit_ascii + || letters && end <= first_letter_ascii) { + throw new IllegalArgumentException("Parameter end (" + end + ") must be greater then (" + zero_digit_ascii + ") for generating digits " + + "or greater then (" + first_letter_ascii + ") for generating letters."); + } + } + + StringBuilder builder = new StringBuilder(count); + final int gap = end - start; + + while (count-- != 0) { + int codePoint; + if (chars == null) { + codePoint = random.nextInt(gap) + start; + + switch (Character.getType(codePoint)) { + case Character.UNASSIGNED: + case Character.PRIVATE_USE: + case Character.SURROGATE: + count++; + continue; + } + + } else { + codePoint = chars[random.nextInt(gap) + start]; + } + + final int numberOfChars = Character.charCount(codePoint); + if (count == 0 && numberOfChars > 1) { + count++; + continue; + } + + if (letters && Character.isLetter(codePoint) + || numbers && Character.isDigit(codePoint) + || !letters && !numbers) { + builder.appendCodePoint(codePoint); + + if (numberOfChars == 2) { + count--; + } + + } else { + count++; + } + } + return builder.toString(); + } + + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of characters + * specified by the string, must not be empty. + * If null, the set of all characters is used.

              + * + * @param count the length of random string to create + * @param chars the String containing the set of characters to use, + * may be null, but must not be empty + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0 or the string is empty. + */ + public static String random(final int count, final String chars) { + if (chars == null) { + return random(count, 0, 0, false, false, null, RANDOM); + } + return random(count, chars.toCharArray()); + } + + /** + *

              Creates a random string whose length is the number of characters + * specified.

              + * + *

              Characters will be chosen from the set of characters specified.

              + * + * @param count the length of random string to create + * @param chars the character array containing the set of characters to use, + * may be null + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + */ + public static String random(final int count, final char... chars) { + if (chars == null) { + return random(count, 0, 0, false, false, null, RANDOM); + } + return random(count, 0, chars.length, false, false, chars, RANDOM); + } + +} diff --git a/src/org/apache/commons/lang3/RandomUtils.java b/src/org/apache/commons/lang3/RandomUtils.java new file mode 100644 index 0000000..3ea4493 --- /dev/null +++ b/src/org/apache/commons/lang3/RandomUtils.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.util.Random; + +/** + *

              Utility library that supplements the standard {@link Random} class.

              + * + * @since 3.3 + */ +public class RandomUtils { + + /** + * Random object used by random method. This has to be not local to the + * random method so as to not return the same value in the same millisecond. + */ + private static final Random RANDOM = new Random(); + + /** + *

              + * {@code RandomUtils} instances should NOT be constructed in standard + * programming. Instead, the class should be used as + * {@code RandomUtils.nextBytes(5);}. + *

              + * + *

              + * This constructor is public to permit tools that require a JavaBean + * instance to operate. + *

              + */ + public RandomUtils() { + super(); + } + + /** + *

              + * Returns a random boolean value + *

              + * + * @return the random boolean + * @since 3.5 + */ + public static boolean nextBoolean() { + return RANDOM.nextBoolean(); + } + + /** + *

              + * Creates an array of random bytes. + *

              + * + * @param count + * the size of the returned array + * @return the random byte array + * @throws IllegalArgumentException if {@code count} is negative + */ + public static byte[] nextBytes(final int count) { + Validate.isTrue(count >= 0, "Count cannot be negative."); + + final byte[] result = new byte[count]; + RANDOM.nextBytes(result); + return result; + } + + /** + *

              + * Returns a random integer within the specified range. + *

              + * + * @param startInclusive + * the smallest value that can be returned, must be non-negative + * @param endExclusive + * the upper bound (not included) + * @throws IllegalArgumentException + * if {@code startInclusive > endExclusive} or if + * {@code startInclusive} is negative + * @return the random integer + */ + public static int nextInt(final int startInclusive, final int endExclusive) { + Validate.isTrue(endExclusive >= startInclusive, + "Start value must be smaller or equal to end value."); + Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); + + if (startInclusive == endExclusive) { + return startInclusive; + } + + return startInclusive + RANDOM.nextInt(endExclusive - startInclusive); + } + + /** + *

              Returns a random int within 0 - Integer.MAX_VALUE

              + * + * @return the random integer + * @see #nextInt(int, int) + * @since 3.5 + */ + public static int nextInt() { + return nextInt(0, Integer.MAX_VALUE); + } + + /** + *

              + * Returns a random long within the specified range. + *

              + * + * @param startInclusive + * the smallest value that can be returned, must be non-negative + * @param endExclusive + * the upper bound (not included) + * @throws IllegalArgumentException + * if {@code startInclusive > endExclusive} or if + * {@code startInclusive} is negative + * @return the random long + */ + public static long nextLong(final long startInclusive, final long endExclusive) { + Validate.isTrue(endExclusive >= startInclusive, + "Start value must be smaller or equal to end value."); + Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); + + if (startInclusive == endExclusive) { + return startInclusive; + } + + return (long) nextDouble(startInclusive, endExclusive); + } + + /** + *

              Returns a random long within 0 - Long.MAX_VALUE

              + * + * @return the random long + * @see #nextLong(long, long) + * @since 3.5 + */ + public static long nextLong() { + return nextLong(0, Long.MAX_VALUE); + } + + /** + *

              + * Returns a random double within the specified range. + *

              + * + * @param startInclusive + * the smallest value that can be returned, must be non-negative + * @param endInclusive + * the upper bound (included) + * @throws IllegalArgumentException + * if {@code startInclusive > endInclusive} or if + * {@code startInclusive} is negative + * @return the random double + */ + public static double nextDouble(final double startInclusive, final double endInclusive) { + Validate.isTrue(endInclusive >= startInclusive, + "Start value must be smaller or equal to end value."); + Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); + + if (startInclusive == endInclusive) { + return startInclusive; + } + + return startInclusive + ((endInclusive - startInclusive) * RANDOM.nextDouble()); + } + + /** + *

              Returns a random double within 0 - Double.MAX_VALUE

              + * + * @return the random double + * @see #nextDouble(double, double) + * @since 3.5 + */ + public static double nextDouble() { + return nextDouble(0, Double.MAX_VALUE); + } + + /** + *

              + * Returns a random float within the specified range. + *

              + * + * @param startInclusive + * the smallest value that can be returned, must be non-negative + * @param endInclusive + * the upper bound (included) + * @throws IllegalArgumentException + * if {@code startInclusive > endInclusive} or if + * {@code startInclusive} is negative + * @return the random float + */ + public static float nextFloat(final float startInclusive, final float endInclusive) { + Validate.isTrue(endInclusive >= startInclusive, + "Start value must be smaller or equal to end value."); + Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); + + if (startInclusive == endInclusive) { + return startInclusive; + } + + return startInclusive + ((endInclusive - startInclusive) * RANDOM.nextFloat()); + } + + /** + *

              Returns a random float within 0 - Float.MAX_VALUE

              + * + * @return the random float + * @see #nextFloat() + * @since 3.5 + */ + public static float nextFloat() { + return nextFloat(0, Float.MAX_VALUE); + } +} diff --git a/src/org/apache/commons/lang3/Range.java b/src/org/apache/commons/lang3/Range.java new file mode 100644 index 0000000..73e6969 --- /dev/null +++ b/src/org/apache/commons/lang3/Range.java @@ -0,0 +1,487 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.Serializable; +import java.util.Comparator; + +/** + *

              An immutable range of objects from a minimum to maximum point inclusive.

              + * + *

              The objects need to either be implementations of {@code Comparable} + * or you need to supply a {@code Comparator}.

              + * + *

              #ThreadSafe# if the objects and comparator are thread-safe

              + * + * @since 3.0 + */ +public final class Range implements Serializable { + + /** + * Serialization version. + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1L; + + /** + * The ordering scheme used in this range. + */ + private final Comparator comparator; + /** + * The minimum value in this range (inclusive). + */ + private final T minimum; + /** + * The maximum value in this range (inclusive). + */ + private final T maximum; + /** + * Cached output hashCode (class is immutable). + */ + private transient int hashCode; + /** + * Cached output toString (class is immutable). + */ + private transient String toString; + + /** + *

              Obtains a range using the specified element as both the minimum + * and maximum in this range.

              + * + *

              The range uses the natural ordering of the elements to determine where + * values lie in the range.

              + * + * @param the type of the elements in this range + * @param element the value to use for this range, not null + * @return the range object, not null + * @throws IllegalArgumentException if the element is null + * @throws ClassCastException if the element is not {@code Comparable} + */ + public static > Range is(final T element) { + return between(element, element, null); + } + + /** + *

              Obtains a range using the specified element as both the minimum + * and maximum in this range.

              + * + *

              The range uses the specified {@code Comparator} to determine where + * values lie in the range.

              + * + * @param the type of the elements in this range + * @param element the value to use for this range, must not be {@code null} + * @param comparator the comparator to be used, null for natural ordering + * @return the range object, not null + * @throws IllegalArgumentException if the element is null + * @throws ClassCastException if using natural ordering and the elements are not {@code Comparable} + */ + public static Range is(final T element, final Comparator comparator) { + return between(element, element, comparator); + } + + /** + *

              Obtains a range with the specified minimum and maximum values (both inclusive).

              + * + *

              The range uses the natural ordering of the elements to determine where + * values lie in the range.

              + * + *

              The arguments may be passed in the order (min,max) or (max,min). + * The getMinimum and getMaximum methods will return the correct values.

              + * + * @param the type of the elements in this range + * @param fromInclusive the first value that defines the edge of the range, inclusive + * @param toInclusive the second value that defines the edge of the range, inclusive + * @return the range object, not null + * @throws IllegalArgumentException if either element is null + * @throws ClassCastException if the elements are not {@code Comparable} + */ + public static > Range between(final T fromInclusive, final T toInclusive) { + return between(fromInclusive, toInclusive, null); + } + + /** + *

              Obtains a range with the specified minimum and maximum values (both inclusive).

              + * + *

              The range uses the specified {@code Comparator} to determine where + * values lie in the range.

              + * + *

              The arguments may be passed in the order (min,max) or (max,min). + * The getMinimum and getMaximum methods will return the correct values.

              + * + * @param the type of the elements in this range + * @param fromInclusive the first value that defines the edge of the range, inclusive + * @param toInclusive the second value that defines the edge of the range, inclusive + * @param comparator the comparator to be used, null for natural ordering + * @return the range object, not null + * @throws IllegalArgumentException if either element is null + * @throws ClassCastException if using natural ordering and the elements are not {@code Comparable} + */ + public static Range between(final T fromInclusive, final T toInclusive, final Comparator comparator) { + return new Range<>(fromInclusive, toInclusive, comparator); + } + + /** + * Creates an instance. + * + * @param element1 the first element, not null + * @param element2 the second element, not null + * @param comp the comparator to be used, null for natural ordering + */ + @SuppressWarnings("unchecked") + private Range(final T element1, final T element2, final Comparator comp) { + if (element1 == null || element2 == null) { + throw new IllegalArgumentException("Elements in a range must not be null: element1=" + + element1 + ", element2=" + element2); + } + if (comp == null) { + this.comparator = ComparableComparator.INSTANCE; + } else { + this.comparator = comp; + } + if (this.comparator.compare(element1, element2) < 1) { + this.minimum = element1; + this.maximum = element2; + } else { + this.minimum = element2; + this.maximum = element1; + } + } + + // Accessors + //-------------------------------------------------------------------- + + /** + *

              Gets the minimum value in this range.

              + * + * @return the minimum value in this range, not null + */ + public T getMinimum() { + return minimum; + } + + /** + *

              Gets the maximum value in this range.

              + * + * @return the maximum value in this range, not null + */ + public T getMaximum() { + return maximum; + } + + /** + *

              Gets the comparator being used to determine if objects are within the range.

              + * + *

              Natural ordering uses an internal comparator implementation, thus this + * method never returns null. See {@link #isNaturalOrdering()}.

              + * + * @return the comparator being used, not null + */ + public Comparator getComparator() { + return comparator; + } + + /** + *

              Whether or not the Range is using the natural ordering of the elements.

              + * + *

              Natural ordering uses an internal comparator implementation, thus this + * method is the only way to check if a null comparator was specified.

              + * + * @return true if using natural ordering + */ + public boolean isNaturalOrdering() { + return comparator == ComparableComparator.INSTANCE; + } + + // Element tests + //-------------------------------------------------------------------- + + /** + *

              Checks whether the specified element occurs within this range.

              + * + * @param element the element to check for, null returns false + * @return true if the specified element occurs within this range + */ + public boolean contains(final T element) { + if (element == null) { + return false; + } + return comparator.compare(element, minimum) > -1 && comparator.compare(element, maximum) < 1; + } + + /** + *

              Checks whether this range is after the specified element.

              + * + * @param element the element to check for, null returns false + * @return true if this range is entirely after the specified element + */ + public boolean isAfter(final T element) { + if (element == null) { + return false; + } + return comparator.compare(element, minimum) < 0; + } + + /** + *

              Checks whether this range starts with the specified element.

              + * + * @param element the element to check for, null returns false + * @return true if the specified element occurs within this range + */ + public boolean isStartedBy(final T element) { + if (element == null) { + return false; + } + return comparator.compare(element, minimum) == 0; + } + + /** + *

              Checks whether this range ends with the specified element.

              + * + * @param element the element to check for, null returns false + * @return true if the specified element occurs within this range + */ + public boolean isEndedBy(final T element) { + if (element == null) { + return false; + } + return comparator.compare(element, maximum) == 0; + } + + /** + *

              Checks whether this range is before the specified element.

              + * + * @param element the element to check for, null returns false + * @return true if this range is entirely before the specified element + */ + public boolean isBefore(final T element) { + if (element == null) { + return false; + } + return comparator.compare(element, maximum) > 0; + } + + /** + *

              Checks where the specified element occurs relative to this range.

              + * + *

              The API is reminiscent of the Comparable interface returning {@code -1} if + * the element is before the range, {@code 0} if contained within the range and + * {@code 1} if the element is after the range.

              + * + * @param element the element to check for, not null + * @return -1, 0 or +1 depending on the element's location relative to the range + */ + public int elementCompareTo(final T element) { + if (element == null) { + // Comparable API says throw NPE on null + throw new NullPointerException("Element is null"); + } + if (isAfter(element)) { + return -1; + } else if (isBefore(element)) { + return 1; + } else { + return 0; + } + } + + // Range tests + //-------------------------------------------------------------------- + + /** + *

              Checks whether this range contains all the elements of the specified range.

              + * + *

              This method may fail if the ranges have two different comparators or element types.

              + * + * @param otherRange the range to check, null returns false + * @return true if this range contains the specified range + * @throws RuntimeException if ranges cannot be compared + */ + public boolean containsRange(final Range otherRange) { + if (otherRange == null) { + return false; + } + return contains(otherRange.minimum) + && contains(otherRange.maximum); + } + + /** + *

              Checks whether this range is completely after the specified range.

              + * + *

              This method may fail if the ranges have two different comparators or element types.

              + * + * @param otherRange the range to check, null returns false + * @return true if this range is completely after the specified range + * @throws RuntimeException if ranges cannot be compared + */ + public boolean isAfterRange(final Range otherRange) { + if (otherRange == null) { + return false; + } + return isAfter(otherRange.maximum); + } + + /** + *

              Checks whether this range is overlapped by the specified range.

              + * + *

              Two ranges overlap if there is at least one element in common.

              + * + *

              This method may fail if the ranges have two different comparators or element types.

              + * + * @param otherRange the range to test, null returns false + * @return true if the specified range overlaps with this + * range; otherwise, {@code false} + * @throws RuntimeException if ranges cannot be compared + */ + public boolean isOverlappedBy(final Range otherRange) { + if (otherRange == null) { + return false; + } + return otherRange.contains(minimum) + || otherRange.contains(maximum) + || contains(otherRange.minimum); + } + + /** + *

              Checks whether this range is completely before the specified range.

              + * + *

              This method may fail if the ranges have two different comparators or element types.

              + * + * @param otherRange the range to check, null returns false + * @return true if this range is completely before the specified range + * @throws RuntimeException if ranges cannot be compared + */ + public boolean isBeforeRange(final Range otherRange) { + if (otherRange == null) { + return false; + } + return isBefore(otherRange.minimum); + } + + /** + * Calculate the intersection of {@code this} and an overlapping Range. + * @param other overlapping Range + * @return range representing the intersection of {@code this} and {@code other} ({@code this} if equal) + * @throws IllegalArgumentException if {@code other} does not overlap {@code this} + * @since 3.0.1 + */ + public Range intersectionWith(final Range other) { + if (!this.isOverlappedBy(other)) { + throw new IllegalArgumentException(String.format( + "Cannot calculate intersection with non-overlapping range %s", other)); + } + if (this.equals(other)) { + return this; + } + final T min = getComparator().compare(minimum, other.minimum) < 0 ? other.minimum : minimum; + final T max = getComparator().compare(maximum, other.maximum) < 0 ? maximum : other.maximum; + return between(min, max, getComparator()); + } + + // Basics + //-------------------------------------------------------------------- + + /** + *

              Compares this range to another object to test if they are equal.

              . + * + *

              To be equal, the minimum and maximum values must be equal, which + * ignores any differences in the comparator.

              + * + * @param obj the reference object with which to compare + * @return true if this object is equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } else if (obj == null || obj.getClass() != getClass()) { + return false; + } else { + @SuppressWarnings("unchecked") // OK because we checked the class above + final + Range range = (Range) obj; + return minimum.equals(range.minimum) && + maximum.equals(range.maximum); + } + } + + /** + *

              Gets a suitable hash code for the range.

              + * + * @return a hash code value for this object + */ + @Override + public int hashCode() { + int result = hashCode; + if (hashCode == 0) { + result = 17; + result = 37 * result + getClass().hashCode(); + result = 37 * result + minimum.hashCode(); + result = 37 * result + maximum.hashCode(); + hashCode = result; + } + return result; + } + + /** + *

              Gets the range as a {@code String}.

              + * + *

              The format of the String is '[min..max]'.

              + * + * @return the {@code String} representation of this range + */ + @Override + public String toString() { + if (toString == null) { + toString = "[" + minimum + ".." + maximum + "]"; + } + return toString; + } + + /** + *

              Formats the receiver using the given format.

              + * + *

              This uses {@link java.util.Formattable} to perform the formatting. Three variables may + * be used to embed the minimum, maximum and comparator. + * Use {@code %1$s} for the minimum element, {@code %2$s} for the maximum element + * and {@code %3$s} for the comparator. + * The default format used by {@code toString()} is {@code [%1$s..%2$s]}.

              + * + * @param format the format string, optionally containing {@code %1$s}, {@code %2$s} and {@code %3$s}, not null + * @return the formatted string, not null + */ + public String toString(final String format) { + return String.format(format, minimum, maximum, comparator); + } + + //----------------------------------------------------------------------- + @SuppressWarnings({"rawtypes", "unchecked"}) + private enum ComparableComparator implements Comparator { + INSTANCE; + /** + * Comparable based compare implementation. + * + * @param obj1 left hand side of comparison + * @param obj2 right hand side of comparison + * @return negative, 0, positive comparison value + */ + @Override + public int compare(final Object obj1, final Object obj2) { + return ((Comparable) obj1).compareTo(obj2); + } + } + +} diff --git a/src/org/apache/commons/lang3/SerializationException.java b/src/org/apache/commons/lang3/SerializationException.java new file mode 100644 index 0000000..588eff0 --- /dev/null +++ b/src/org/apache/commons/lang3/SerializationException.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +/** + *

              Exception thrown when the Serialization process fails.

              + * + *

              The original error is wrapped within this one.

              + * + *

              #NotThreadSafe# because Throwable is not thread-safe

              + * @since 1.0 + */ +public class SerializationException extends RuntimeException { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 4029025366392702726L; + + /** + *

              Constructs a new {@code SerializationException} without specified + * detail message.

              + */ + public SerializationException() { + super(); + } + + /** + *

              Constructs a new {@code SerializationException} with specified + * detail message.

              + * + * @param msg The error message. + */ + public SerializationException(final String msg) { + super(msg); + } + + /** + *

              Constructs a new {@code SerializationException} with specified + * nested {@code Throwable}.

              + * + * @param cause The {@code Exception} or {@code Error} + * that caused this exception to be thrown. + */ + public SerializationException(final Throwable cause) { + super(cause); + } + + /** + *

              Constructs a new {@code SerializationException} with specified + * detail message and nested {@code Throwable}.

              + * + * @param msg The error message. + * @param cause The {@code Exception} or {@code Error} + * that caused this exception to be thrown. + */ + public SerializationException(final String msg, final Throwable cause) { + super(msg, cause); + } + +} diff --git a/src/org/apache/commons/lang3/SerializationUtils.java b/src/org/apache/commons/lang3/SerializationUtils.java new file mode 100644 index 0000000..f1a4993 --- /dev/null +++ b/src/org/apache/commons/lang3/SerializationUtils.java @@ -0,0 +1,303 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + *

              Assists with the serialization process and performs additional functionality based + * on serialization.

              + * + *
                + *
              • Deep clone using serialization + *
              • Serialize managing finally and IOException + *
              • Deserialize managing finally and IOException + *
              + * + *

              This class throws exceptions for invalid {@code null} inputs. + * Each method documents its behaviour in more detail.

              + * + *

              #ThreadSafe#

              + * @since 1.0 + */ +public class SerializationUtils { + + /** + *

              SerializationUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code SerializationUtils.clone(object)}.

              + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate.

              + * @since 2.0 + */ + public SerializationUtils() { + super(); + } + + // Clone + //----------------------------------------------------------------------- + /** + *

              Deep clone an {@code Object} using serialization.

              + * + *

              This is many times slower than writing clone methods by hand + * on all objects in your object graph. However, for complex object + * graphs, or for those that don't support deep cloning this can + * be a simple alternative implementation. Of course all the objects + * must be {@code Serializable}.

              + * + * @param the type of the object involved + * @param object the {@code Serializable} object to clone + * @return the cloned object + * @throws SerializationException (runtime) if the serialization fails + */ + public static T clone(final T object) { + if (object == null) { + return null; + } + final byte[] objectData = serialize(object); + final ByteArrayInputStream bais = new ByteArrayInputStream(objectData); + + try (final ClassLoaderAwareObjectInputStream in = new ClassLoaderAwareObjectInputStream(bais, + object.getClass().getClassLoader())) { + /* + * when we serialize and deserialize an object, + * it is reasonable to assume the deserialized object + * is of the same type as the original serialized object + */ + @SuppressWarnings("unchecked") // see above + final T readObject = (T) in.readObject(); + return readObject; + + } catch (final ClassNotFoundException ex) { + throw new SerializationException("ClassNotFoundException while reading cloned object data", ex); + } catch (final IOException ex) { + throw new SerializationException("IOException while reading or closing cloned object data", ex); + } + } + + /** + * Performs a serialization roundtrip. Serializes and deserializes the given object, great for testing objects that + * implement {@link Serializable}. + * + * @param + * the type of the object involved + * @param msg + * the object to roundtrip + * @return the serialized and deserialized object + * @since 3.3 + */ + @SuppressWarnings("unchecked") // OK, because we serialized a type `T` + public static T roundtrip(final T msg) { + return (T) SerializationUtils.deserialize(SerializationUtils.serialize(msg)); + } + + // Serialize + //----------------------------------------------------------------------- + /** + *

              Serializes an {@code Object} to the specified stream.

              + * + *

              The stream will be closed once the object is written. + * This avoids the need for a finally clause, and maybe also exception + * handling, in the application code.

              + * + *

              The stream passed in is not buffered internally within this method. + * This is the responsibility of your application if desired.

              + * + * @param obj the object to serialize to bytes, may be null + * @param outputStream the stream to write to, must not be null + * @throws IllegalArgumentException if {@code outputStream} is {@code null} + * @throws SerializationException (runtime) if the serialization fails + */ + public static void serialize(final Serializable obj, final OutputStream outputStream) { + if (outputStream == null) { + throw new IllegalArgumentException("The OutputStream must not be null"); + } + try (ObjectOutputStream out = new ObjectOutputStream(outputStream)){ + out.writeObject(obj); + } catch (final IOException ex) { + throw new SerializationException(ex); + } + } + + /** + *

              Serializes an {@code Object} to a byte array for + * storage/serialization.

              + * + * @param obj the object to serialize to bytes + * @return a byte[] with the converted Serializable + * @throws SerializationException (runtime) if the serialization fails + */ + public static byte[] serialize(final Serializable obj) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(512); + serialize(obj, baos); + return baos.toByteArray(); + } + + // Deserialize + //----------------------------------------------------------------------- + /** + *

              + * Deserializes an {@code Object} from the specified stream. + *

              + * + *

              + * The stream will be closed once the object is written. This avoids the need for a finally clause, and maybe also + * exception handling, in the application code. + *

              + * + *

              + * The stream passed in is not buffered internally within this method. This is the responsibility of your + * application if desired. + *

              + * + *

              + * If the call site incorrectly types the return value, a {@link ClassCastException} is thrown from the call site. + * Without Generics in this declaration, the call site must type cast and can cause the same ClassCastException. + * Note that in both cases, the ClassCastException is in the call site, not in this method. + *

              + * + * @param the object type to be deserialized + * @param inputStream + * the serialized object input stream, must not be null + * @return the deserialized object + * @throws IllegalArgumentException + * if {@code inputStream} is {@code null} + * @throws SerializationException + * (runtime) if the serialization fails + */ + public static T deserialize(final InputStream inputStream) { + if (inputStream == null) { + throw new IllegalArgumentException("The InputStream must not be null"); + } + try (ObjectInputStream in = new ObjectInputStream(inputStream)) { + @SuppressWarnings("unchecked") + final T obj = (T) in.readObject(); + return obj; + } catch (final ClassNotFoundException | IOException ex) { + throw new SerializationException(ex); + } + } + + /** + *

              + * Deserializes a single {@code Object} from an array of bytes. + *

              + * + *

              + * If the call site incorrectly types the return value, a {@link ClassCastException} is thrown from the call site. + * Without Generics in this declaration, the call site must type cast and can cause the same ClassCastException. + * Note that in both cases, the ClassCastException is in the call site, not in this method. + *

              + * + * @param the object type to be deserialized + * @param objectData + * the serialized object, must not be null + * @return the deserialized object + * @throws IllegalArgumentException + * if {@code objectData} is {@code null} + * @throws SerializationException + * (runtime) if the serialization fails + */ + public static T deserialize(final byte[] objectData) { + if (objectData == null) { + throw new IllegalArgumentException("The byte[] must not be null"); + } + return SerializationUtils.deserialize(new ByteArrayInputStream(objectData)); + } + + /** + *

              Custom specialization of the standard JDK {@link java.io.ObjectInputStream} + * that uses a custom ClassLoader to resolve a class. + * If the specified ClassLoader is not able to resolve the class, + * the context classloader of the current thread will be used. + * This way, the standard deserialization work also in web-application + * containers and application servers, no matter in which of the + * ClassLoader the particular class that encapsulates + * serialization/deserialization lives.

              + * + *

              For more in-depth information about the problem for which this + * class here is a workaround, see the JIRA issue LANG-626.

              + */ + static class ClassLoaderAwareObjectInputStream extends ObjectInputStream { + private static final Map> primitiveTypes = + new HashMap<>(); + + static { + primitiveTypes.put("byte", byte.class); + primitiveTypes.put("short", short.class); + primitiveTypes.put("int", int.class); + primitiveTypes.put("long", long.class); + primitiveTypes.put("float", float.class); + primitiveTypes.put("double", double.class); + primitiveTypes.put("boolean", boolean.class); + primitiveTypes.put("char", char.class); + primitiveTypes.put("void", void.class); + } + + private final ClassLoader classLoader; + + /** + * Constructor. + * @param in The InputStream. + * @param classLoader classloader to use + * @throws IOException if an I/O error occurs while reading stream header. + * @see java.io.ObjectInputStream + */ + public ClassLoaderAwareObjectInputStream(final InputStream in, final ClassLoader classLoader) throws IOException { + super(in); + this.classLoader = classLoader; + } + + /** + * Overridden version that uses the parameterized ClassLoader or the ClassLoader + * of the current Thread to resolve the class. + * @param desc An instance of class ObjectStreamClass. + * @return A Class object corresponding to desc. + * @throws IOException Any of the usual Input/Output exceptions. + * @throws ClassNotFoundException If class of a serialized object cannot be found. + */ + @Override + protected Class resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException { + final String name = desc.getName(); + try { + return Class.forName(name, false, classLoader); + } catch (final ClassNotFoundException ex) { + try { + return Class.forName(name, false, Thread.currentThread().getContextClassLoader()); + } catch (final ClassNotFoundException cnfe) { + final Class cls = primitiveTypes.get(name); + if (cls != null) { + return cls; + } + throw cnfe; + } + } + } + + } + +} diff --git a/src/org/apache/commons/lang3/StringEscapeUtils.java b/src/org/apache/commons/lang3/StringEscapeUtils.java new file mode 100644 index 0000000..df2a835 --- /dev/null +++ b/src/org/apache/commons/lang3/StringEscapeUtils.java @@ -0,0 +1,808 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.IOException; +import java.io.Writer; + +import org.apache.commons.lang3.text.translate.AggregateTranslator; +import org.apache.commons.lang3.text.translate.CharSequenceTranslator; +import org.apache.commons.lang3.text.translate.EntityArrays; +import org.apache.commons.lang3.text.translate.JavaUnicodeEscaper; +import org.apache.commons.lang3.text.translate.LookupTranslator; +import org.apache.commons.lang3.text.translate.NumericEntityEscaper; +import org.apache.commons.lang3.text.translate.NumericEntityUnescaper; +import org.apache.commons.lang3.text.translate.OctalUnescaper; +import org.apache.commons.lang3.text.translate.UnicodeUnescaper; +import org.apache.commons.lang3.text.translate.UnicodeUnpairedSurrogateRemover; + +/** + *

              Escapes and unescapes {@code String}s for + * Java, Java Script, HTML and XML.

              + * + *

              #ThreadSafe#

              + * @since 2.0 + * @deprecated as of 3.6, use commons-text + * + * StringEscapeUtils instead + */ +@Deprecated +public class StringEscapeUtils { + + /* ESCAPE TRANSLATORS */ + + /** + * Translator object for escaping Java. + * + * While {@link #escapeJava(String)} is the expected method of use, this + * object allows the Java escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator ESCAPE_JAVA = + new LookupTranslator( + new String[][] { + {"\"", "\\\""}, + {"\\", "\\\\"}, + }).with( + new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()) + ).with( + JavaUnicodeEscaper.outsideOf(32, 0x7f) + ); + + /** + * Translator object for escaping EcmaScript/JavaScript. + * + * While {@link #escapeEcmaScript(String)} is the expected method of use, this + * object allows the EcmaScript escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator ESCAPE_ECMASCRIPT = + new AggregateTranslator( + new LookupTranslator( + new String[][] { + {"'", "\\'"}, + {"\"", "\\\""}, + {"\\", "\\\\"}, + {"/", "\\/"} + }), + new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()), + JavaUnicodeEscaper.outsideOf(32, 0x7f) + ); + + /** + * Translator object for escaping Json. + * + * While {@link #escapeJson(String)} is the expected method of use, this + * object allows the Json escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.2 + */ + public static final CharSequenceTranslator ESCAPE_JSON = + new AggregateTranslator( + new LookupTranslator( + new String[][] { + {"\"", "\\\""}, + {"\\", "\\\\"}, + {"/", "\\/"} + }), + new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE()), + JavaUnicodeEscaper.outsideOf(32, 0x7f) + ); + + /** + * Translator object for escaping XML. + * + * While {@link #escapeXml(String)} is the expected method of use, this + * object allows the XML escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + * @deprecated use {@link #ESCAPE_XML10} or {@link #ESCAPE_XML11} instead. + */ + @Deprecated + public static final CharSequenceTranslator ESCAPE_XML = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_ESCAPE()), + new LookupTranslator(EntityArrays.APOS_ESCAPE()) + ); + + /** + * Translator object for escaping XML 1.0. + * + * While {@link #escapeXml10(String)} is the expected method of use, this + * object allows the XML escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.3 + */ + public static final CharSequenceTranslator ESCAPE_XML10 = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_ESCAPE()), + new LookupTranslator(EntityArrays.APOS_ESCAPE()), + new LookupTranslator( + new String[][] { + { "\u0000", StringUtils.EMPTY }, + { "\u0001", StringUtils.EMPTY }, + { "\u0002", StringUtils.EMPTY }, + { "\u0003", StringUtils.EMPTY }, + { "\u0004", StringUtils.EMPTY }, + { "\u0005", StringUtils.EMPTY }, + { "\u0006", StringUtils.EMPTY }, + { "\u0007", StringUtils.EMPTY }, + { "\u0008", StringUtils.EMPTY }, + { "\u000b", StringUtils.EMPTY }, + { "\u000c", StringUtils.EMPTY }, + { "\u000e", StringUtils.EMPTY }, + { "\u000f", StringUtils.EMPTY }, + { "\u0010", StringUtils.EMPTY }, + { "\u0011", StringUtils.EMPTY }, + { "\u0012", StringUtils.EMPTY }, + { "\u0013", StringUtils.EMPTY }, + { "\u0014", StringUtils.EMPTY }, + { "\u0015", StringUtils.EMPTY }, + { "\u0016", StringUtils.EMPTY }, + { "\u0017", StringUtils.EMPTY }, + { "\u0018", StringUtils.EMPTY }, + { "\u0019", StringUtils.EMPTY }, + { "\u001a", StringUtils.EMPTY }, + { "\u001b", StringUtils.EMPTY }, + { "\u001c", StringUtils.EMPTY }, + { "\u001d", StringUtils.EMPTY }, + { "\u001e", StringUtils.EMPTY }, + { "\u001f", StringUtils.EMPTY }, + { "\ufffe", StringUtils.EMPTY }, + { "\uffff", StringUtils.EMPTY } + }), + NumericEntityEscaper.between(0x7f, 0x84), + NumericEntityEscaper.between(0x86, 0x9f), + new UnicodeUnpairedSurrogateRemover() + ); + + /** + * Translator object for escaping XML 1.1. + * + * While {@link #escapeXml11(String)} is the expected method of use, this + * object allows the XML escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.3 + */ + public static final CharSequenceTranslator ESCAPE_XML11 = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_ESCAPE()), + new LookupTranslator(EntityArrays.APOS_ESCAPE()), + new LookupTranslator( + new String[][] { + { "\u0000", StringUtils.EMPTY }, + { "\u000b", " " }, + { "\u000c", " " }, + { "\ufffe", StringUtils.EMPTY }, + { "\uffff", StringUtils.EMPTY } + }), + NumericEntityEscaper.between(0x1, 0x8), + NumericEntityEscaper.between(0xe, 0x1f), + NumericEntityEscaper.between(0x7f, 0x84), + NumericEntityEscaper.between(0x86, 0x9f), + new UnicodeUnpairedSurrogateRemover() + ); + + /** + * Translator object for escaping HTML version 3.0. + * + * While {@link #escapeHtml3(String)} is the expected method of use, this + * object allows the HTML escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator ESCAPE_HTML3 = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_ESCAPE()), + new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE()) + ); + + /** + * Translator object for escaping HTML version 4.0. + * + * While {@link #escapeHtml4(String)} is the expected method of use, this + * object allows the HTML escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator ESCAPE_HTML4 = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_ESCAPE()), + new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE()), + new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE()) + ); + + /** + * Translator object for escaping individual Comma Separated Values. + * + * While {@link #escapeCsv(String)} is the expected method of use, this + * object allows the CSV escaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator ESCAPE_CSV = new CsvEscaper(); + + // TODO: Create a parent class - 'SinglePassTranslator' ? + // It would handle the index checking + length returning, + // and could also have an optimization check method. + static class CsvEscaper extends CharSequenceTranslator { + + private static final char CSV_DELIMITER = ','; + private static final char CSV_QUOTE = '"'; + private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE); + private static final char[] CSV_SEARCH_CHARS = + new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF}; + + @Override + public int translate(final CharSequence input, final int index, final Writer out) throws IOException { + + if(index != 0) { + throw new IllegalStateException("CsvEscaper should never reach the [1] index"); + } + + if (StringUtils.containsNone(input.toString(), CSV_SEARCH_CHARS)) { + out.write(input.toString()); + } else { + out.write(CSV_QUOTE); + out.write(StringUtils.replace(input.toString(), CSV_QUOTE_STR, CSV_QUOTE_STR + CSV_QUOTE_STR)); + out.write(CSV_QUOTE); + } + return Character.codePointCount(input, 0, input.length()); + } + } + + /* UNESCAPE TRANSLATORS */ + + /** + * Translator object for unescaping escaped Java. + * + * While {@link #unescapeJava(String)} is the expected method of use, this + * object allows the Java unescaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + // TODO: throw "illegal character: \92" as an Exception if a \ on the end of the Java (as per the compiler)? + public static final CharSequenceTranslator UNESCAPE_JAVA = + new AggregateTranslator( + new OctalUnescaper(), // .between('\1', '\377'), + new UnicodeUnescaper(), + new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE()), + new LookupTranslator( + new String[][] { + {"\\\\", "\\"}, + {"\\\"", "\""}, + {"\\'", "'"}, + {"\\", ""} + }) + ); + + /** + * Translator object for unescaping escaped EcmaScript. + * + * While {@link #unescapeEcmaScript(String)} is the expected method of use, this + * object allows the EcmaScript unescaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA; + + /** + * Translator object for unescaping escaped Json. + * + * While {@link #unescapeJson(String)} is the expected method of use, this + * object allows the Json unescaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.2 + */ + public static final CharSequenceTranslator UNESCAPE_JSON = UNESCAPE_JAVA; + + /** + * Translator object for unescaping escaped HTML 3.0. + * + * While {@link #unescapeHtml3(String)} is the expected method of use, this + * object allows the HTML unescaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator UNESCAPE_HTML3 = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_UNESCAPE()), + new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()), + new NumericEntityUnescaper() + ); + + /** + * Translator object for unescaping escaped HTML 4.0. + * + * While {@link #unescapeHtml4(String)} is the expected method of use, this + * object allows the HTML unescaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator UNESCAPE_HTML4 = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_UNESCAPE()), + new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()), + new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE()), + new NumericEntityUnescaper() + ); + + /** + * Translator object for unescaping escaped XML. + * + * While {@link #unescapeXml(String)} is the expected method of use, this + * object allows the XML unescaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator UNESCAPE_XML = + new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_UNESCAPE()), + new LookupTranslator(EntityArrays.APOS_UNESCAPE()), + new NumericEntityUnescaper() + ); + + /** + * Translator object for unescaping escaped Comma Separated Value entries. + * + * While {@link #unescapeCsv(String)} is the expected method of use, this + * object allows the CSV unescaping functionality to be used + * as the foundation for a custom translator. + * + * @since 3.0 + */ + public static final CharSequenceTranslator UNESCAPE_CSV = new CsvUnescaper(); + + static class CsvUnescaper extends CharSequenceTranslator { + + private static final char CSV_DELIMITER = ','; + private static final char CSV_QUOTE = '"'; + private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE); + private static final char[] CSV_SEARCH_CHARS = + new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF}; + + @Override + public int translate(final CharSequence input, final int index, final Writer out) throws IOException { + + if(index != 0) { + throw new IllegalStateException("CsvUnescaper should never reach the [1] index"); + } + + if ( input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE ) { + out.write(input.toString()); + return Character.codePointCount(input, 0, input.length()); + } + + // strip quotes + final String quoteless = input.subSequence(1, input.length() - 1).toString(); + + if ( StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS) ) { + // deal with escaped quotes; ie) "" + out.write(StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QUOTE_STR)); + } else { + out.write(input.toString()); + } + return Character.codePointCount(input, 0, input.length()); + } + } + + /* Helper functions */ + + /** + *

              {@code StringEscapeUtils} instances should NOT be constructed in + * standard programming.

              + * + *

              Instead, the class should be used as:

              + *
              StringEscapeUtils.escapeJava("foo");
              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public StringEscapeUtils() { + super(); + } + + // Java and JavaScript + //-------------------------------------------------------------------------- + /** + *

              Escapes the characters in a {@code String} using Java String rules.

              + * + *

              Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)

              + * + *

              So a tab becomes the characters {@code '\\'} and + * {@code 't'}.

              + * + *

              The only difference between Java strings and JavaScript strings + * is that in JavaScript, a single quote and forward-slash (/) are escaped.

              + * + *

              Example:

              + *
              +     * input string: He didn't say, "Stop!"
              +     * output string: He didn't say, \"Stop!\"
              +     * 
              + * + * @param input String to escape values in, may be null + * @return String with escaped values, {@code null} if null string input + */ + public static final String escapeJava(final String input) { + return ESCAPE_JAVA.translate(input); + } + + /** + *

              Escapes the characters in a {@code String} using EcmaScript String rules.

              + *

              Escapes any values it finds into their EcmaScript String form. + * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)

              + * + *

              So a tab becomes the characters {@code '\\'} and + * {@code 't'}.

              + * + *

              The only difference between Java strings and EcmaScript strings + * is that in EcmaScript, a single quote and forward-slash (/) are escaped.

              + * + *

              Note that EcmaScript is best known by the JavaScript and ActionScript dialects.

              + * + *

              Example:

              + *
              +     * input string: He didn't say, "Stop!"
              +     * output string: He didn\'t say, \"Stop!\"
              +     * 
              + * + * @param input String to escape values in, may be null + * @return String with escaped values, {@code null} if null string input + * + * @since 3.0 + */ + public static final String escapeEcmaScript(final String input) { + return ESCAPE_ECMASCRIPT.translate(input); + } + + /** + *

              Escapes the characters in a {@code String} using Json String rules.

              + *

              Escapes any values it finds into their Json String form. + * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.)

              + * + *

              So a tab becomes the characters {@code '\\'} and + * {@code 't'}.

              + * + *

              The only difference between Java strings and Json strings + * is that in Json, forward-slash (/) is escaped.

              + * + *

              See http://www.ietf.org/rfc/rfc4627.txt for further details.

              + * + *

              Example:

              + *
              +     * input string: He didn't say, "Stop!"
              +     * output string: He didn't say, \"Stop!\"
              +     * 
              + * + * @param input String to escape values in, may be null + * @return String with escaped values, {@code null} if null string input + * + * @since 3.2 + */ + public static final String escapeJson(final String input) { + return ESCAPE_JSON.translate(input); + } + + /** + *

              Unescapes any Java literals found in the {@code String}. + * For example, it will turn a sequence of {@code '\'} and + * {@code 'n'} into a newline character, unless the {@code '\'} + * is preceded by another {@code '\'}.

              + * + * @param input the {@code String} to unescape, may be null + * @return a new unescaped {@code String}, {@code null} if null string input + */ + public static final String unescapeJava(final String input) { + return UNESCAPE_JAVA.translate(input); + } + + /** + *

              Unescapes any EcmaScript literals found in the {@code String}.

              + * + *

              For example, it will turn a sequence of {@code '\'} and {@code 'n'} + * into a newline character, unless the {@code '\'} is preceded by another + * {@code '\'}.

              + * + * @see #unescapeJava(String) + * @param input the {@code String} to unescape, may be null + * @return A new unescaped {@code String}, {@code null} if null string input + * + * @since 3.0 + */ + public static final String unescapeEcmaScript(final String input) { + return UNESCAPE_ECMASCRIPT.translate(input); + } + + /** + *

              Unescapes any Json literals found in the {@code String}.

              + * + *

              For example, it will turn a sequence of {@code '\'} and {@code 'n'} + * into a newline character, unless the {@code '\'} is preceded by another + * {@code '\'}.

              + * + * @see #unescapeJava(String) + * @param input the {@code String} to unescape, may be null + * @return A new unescaped {@code String}, {@code null} if null string input + * + * @since 3.2 + */ + public static final String unescapeJson(final String input) { + return UNESCAPE_JSON.translate(input); + } + + // HTML and XML + //-------------------------------------------------------------------------- + /** + *

              Escapes the characters in a {@code String} using HTML entities.

              + * + *

              + * For example: + *

              + *

              "bread" & "butter"

              + * becomes: + *

              + * &quot;bread&quot; &amp; &quot;butter&quot;. + *

              + * + *

              Supports all known HTML 4.0 entities, including funky accents. + * Note that the commonly used apostrophe escape character (&apos;) + * is not a legal entity and so is not supported).

              + * + * @param input the {@code String} to escape, may be null + * @return a new escaped {@code String}, {@code null} if null string input + * + * @see ISO Entities + * @see HTML 3.2 Character Entities for ISO Latin-1 + * @see HTML 4.0 Character entity references + * @see HTML 4.01 Character References + * @see HTML 4.01 Code positions + * + * @since 3.0 + */ + public static final String escapeHtml4(final String input) { + return ESCAPE_HTML4.translate(input); + } + + /** + *

              Escapes the characters in a {@code String} using HTML entities.

              + *

              Supports only the HTML 3.0 entities.

              + * + * @param input the {@code String} to escape, may be null + * @return a new escaped {@code String}, {@code null} if null string input + * + * @since 3.0 + */ + public static final String escapeHtml3(final String input) { + return ESCAPE_HTML3.translate(input); + } + + //----------------------------------------------------------------------- + /** + *

              Unescapes a string containing entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes. Supports HTML 4.0 entities.

              + * + *

              For example, the string {@code "<Français>"} + * will become {@code ""}

              + * + *

              If an entity is unrecognized, it is left alone, and inserted + * verbatim into the result string. e.g. {@code ">&zzzz;x"} will + * become {@code ">&zzzz;x"}.

              + * + * @param input the {@code String} to unescape, may be null + * @return a new unescaped {@code String}, {@code null} if null string input + * + * @since 3.0 + */ + public static final String unescapeHtml4(final String input) { + return UNESCAPE_HTML4.translate(input); + } + + /** + *

              Unescapes a string containing entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes. Supports only HTML 3.0 entities.

              + * + * @param input the {@code String} to unescape, may be null + * @return a new unescaped {@code String}, {@code null} if null string input + * + * @since 3.0 + */ + public static final String unescapeHtml3(final String input) { + return UNESCAPE_HTML3.translate(input); + } + + //----------------------------------------------------------------------- + /** + *

              Escapes the characters in a {@code String} using XML entities.

              + * + *

              For example: {@code "bread" & "butter"} => + * {@code "bread" & "butter"}. + *

              + * + *

              Supports only the five basic XML entities (gt, lt, quot, amp, apos). + * Does not support DTDs or external entities.

              + * + *

              Note that Unicode characters greater than 0x7f are as of 3.0, no longer + * escaped. If you still wish this functionality, you can achieve it + * via the following: + * {@code StringEscapeUtils.ESCAPE_XML.with( NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE) );}

              + * + * @param input the {@code String} to escape, may be null + * @return a new escaped {@code String}, {@code null} if null string input + * @see #unescapeXml(java.lang.String) + * @deprecated use {@link #escapeXml10(java.lang.String)} or {@link #escapeXml11(java.lang.String)} instead. + */ + @Deprecated + public static final String escapeXml(final String input) { + return ESCAPE_XML.translate(input); + } + + /** + *

              Escapes the characters in a {@code String} using XML entities.

              + * + *

              For example: {@code "bread" & "butter"} => + * {@code "bread" & "butter"}. + *

              + * + *

              Note that XML 1.0 is a text-only format: it cannot represent control + * characters or unpaired Unicode surrogate codepoints, even after escaping. + * {@code escapeXml10} will remove characters that do not fit in the + * following ranges:

              + * + *

              {@code #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}

              + * + *

              Though not strictly necessary, {@code escapeXml10} will escape + * characters in the following ranges:

              + * + *

              {@code [#x7F-#x84] | [#x86-#x9F]}

              + * + *

              The returned string can be inserted into a valid XML 1.0 or XML 1.1 + * document. If you want to allow more non-text characters in an XML 1.1 + * document, use {@link #escapeXml11(String)}.

              + * + * @param input the {@code String} to escape, may be null + * @return a new escaped {@code String}, {@code null} if null string input + * @see #unescapeXml(java.lang.String) + * @since 3.3 + */ + public static String escapeXml10(final String input) { + return ESCAPE_XML10.translate(input); + } + + /** + *

              Escapes the characters in a {@code String} using XML entities.

              + * + *

              For example: {@code "bread" & "butter"} => + * {@code "bread" & "butter"}. + *

              + * + *

              XML 1.1 can represent certain control characters, but it cannot represent + * the null byte or unpaired Unicode surrogate codepoints, even after escaping. + * {@code escapeXml11} will remove characters that do not fit in the following + * ranges:

              + * + *

              {@code [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}

              + * + *

              {@code escapeXml11} will escape characters in the following ranges:

              + * + *

              {@code [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]}

              + * + *

              The returned string can be inserted into a valid XML 1.1 document. Do not + * use it for XML 1.0 documents.

              + * + * @param input the {@code String} to escape, may be null + * @return a new escaped {@code String}, {@code null} if null string input + * @see #unescapeXml(java.lang.String) + * @since 3.3 + */ + public static String escapeXml11(final String input) { + return ESCAPE_XML11.translate(input); + } + + //----------------------------------------------------------------------- + /** + *

              Unescapes a string containing XML entity escapes to a string + * containing the actual Unicode characters corresponding to the + * escapes.

              + * + *

              Supports only the five basic XML entities (gt, lt, quot, amp, apos). + * Does not support DTDs or external entities.

              + * + *

              Note that numerical \\u Unicode codes are unescaped to their respective + * Unicode characters. This may change in future releases.

              + * + * @param input the {@code String} to unescape, may be null + * @return a new unescaped {@code String}, {@code null} if null string input + * @see #escapeXml(String) + * @see #escapeXml10(String) + * @see #escapeXml11(String) + */ + public static final String unescapeXml(final String input) { + return UNESCAPE_XML.translate(input); + } + + //----------------------------------------------------------------------- + + /** + *

              Returns a {@code String} value for a CSV column enclosed in double quotes, + * if required.

              + * + *

              If the value contains a comma, newline or double quote, then the + * String value is returned enclosed in double quotes.

              + * + *

              Any double quote characters in the value are escaped with another double quote.

              + * + *

              If the value does not contain a comma, newline or double quote, then the + * String value is returned unchanged.

              + * + * see Wikipedia and + * RFC 4180. + * + * @param input the input CSV column String, may be null + * @return the input String, enclosed in double quotes if the value contains a comma, + * newline or double quote, {@code null} if null string input + * @since 2.4 + */ + public static final String escapeCsv(final String input) { + return ESCAPE_CSV.translate(input); + } + + /** + *

              Returns a {@code String} value for an unescaped CSV column.

              + * + *

              If the value is enclosed in double quotes, and contains a comma, newline + * or double quote, then quotes are removed. + *

              + * + *

              Any double quote escaped characters (a pair of double quotes) are unescaped + * to just one double quote.

              + * + *

              If the value is not enclosed in double quotes, or is and does not contain a + * comma, newline or double quote, then the String value is returned unchanged.

              + * + * see Wikipedia and + * RFC 4180. + * + * @param input the input CSV column String, may be null + * @return the input String, with enclosing double quotes removed and embedded double + * quotes unescaped, {@code null} if null string input + * @since 2.4 + */ + public static final String unescapeCsv(final String input) { + return UNESCAPE_CSV.translate(input); + } + +} diff --git a/src/org/apache/commons/lang3/StringUtils.java b/src/org/apache/commons/lang3/StringUtils.java new file mode 100644 index 0000000..bd660bc --- /dev/null +++ b/src/org/apache/commons/lang3/StringUtils.java @@ -0,0 +1,9174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.text.Normalizer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + *

              Operations on {@link java.lang.String} that are + * {@code null} safe.

              + * + *
                + *
              • IsEmpty/IsBlank + * - checks if a String contains text
              • + *
              • Trim/Strip + * - removes leading and trailing whitespace
              • + *
              • Equals/Compare + * - compares two strings null-safe
              • + *
              • startsWith + * - check if a String starts with a prefix null-safe
              • + *
              • endsWith + * - check if a String ends with a suffix null-safe
              • + *
              • IndexOf/LastIndexOf/Contains + * - null-safe index-of checks + *
              • IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut + * - index-of any of a set of Strings
              • + *
              • ContainsOnly/ContainsNone/ContainsAny + * - does String contains only/none/any of these characters
              • + *
              • Substring/Left/Right/Mid + * - null-safe substring extractions
              • + *
              • SubstringBefore/SubstringAfter/SubstringBetween + * - substring extraction relative to other strings
              • + *
              • Split/Join + * - splits a String into an array of substrings and vice versa
              • + *
              • Remove/Delete + * - removes part of a String
              • + *
              • Replace/Overlay + * - Searches a String and replaces one String with another
              • + *
              • Chomp/Chop + * - removes the last part of a String
              • + *
              • AppendIfMissing + * - appends a suffix to the end of the String if not present
              • + *
              • PrependIfMissing + * - prepends a prefix to the start of the String if not present
              • + *
              • LeftPad/RightPad/Center/Repeat + * - pads a String
              • + *
              • UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize + * - changes the case of a String
              • + *
              • CountMatches + * - counts the number of occurrences of one String in another
              • + *
              • IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable + * - checks the characters in a String
              • + *
              • DefaultString + * - protects against a null input String
              • + *
              • Rotate + * - rotate (circular shift) a String
              • + *
              • Reverse/ReverseDelimited + * - reverses a String
              • + *
              • Abbreviate + * - abbreviates a string using ellipsis or another given String
              • + *
              • Difference + * - compares Strings and reports on their differences
              • + *
              • LevenshteinDistance + * - the number of changes needed to change one String into another
              • + *
              + * + *

              The {@code StringUtils} class defines certain words related to + * String handling.

              + * + *
                + *
              • null - {@code null}
              • + *
              • empty - a zero-length string ({@code ""})
              • + *
              • space - the space character ({@code ' '}, char 32)
              • + *
              • whitespace - the characters defined by {@link Character#isWhitespace(char)}
              • + *
              • trim - the characters <= 32 as in {@link String#trim()}
              • + *
              + * + *

              {@code StringUtils} handles {@code null} input Strings quietly. + * That is to say that a {@code null} input will return {@code null}. + * Where a {@code boolean} or {@code int} is being returned + * details vary by method.

              + * + *

              A side effect of the {@code null} handling is that a + * {@code NullPointerException} should be considered a bug in + * {@code StringUtils}.

              + * + *

              Methods in this class give sample code to explain their operation. + * The symbol {@code *} is used to indicate any input including {@code null}.

              + * + *

              #ThreadSafe#

              + * @see java.lang.String + * @since 1.0 + */ +//@Immutable +public class StringUtils { + // Performance testing notes (JDK 1.4, Jul03, scolebourne) + // Whitespace: + // Character.isWhitespace() is faster than WHITESPACE.indexOf() + // where WHITESPACE is a string of all whitespace characters + // + // Character access: + // String.charAt(n) versus toCharArray(), then array[n] + // String.charAt(n) is about 15% worse for a 10K string + // They are about equal for a length 50 string + // String.charAt(n) is about 4 times better for a length 3 string + // String.charAt(n) is best bet overall + // + // Append: + // String.concat about twice as fast as StringBuffer.append + // (not sure who tested this) + + /** + * A String for a space character. + * + * @since 3.2 + */ + public static final String SPACE = " "; + + /** + * The empty String {@code ""}. + * @since 2.0 + */ + public static final String EMPTY = ""; + + /** + * A String for linefeed LF ("\n"). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 3.2 + */ + public static final String LF = "\n"; + + /** + * A String for carriage return CR ("\r"). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 3.2 + */ + public static final String CR = "\r"; + + /** + * Represents a failed index search. + * @since 2.1 + */ + public static final int INDEX_NOT_FOUND = -1; + + /** + *

              The maximum size to which the padding constant(s) can expand.

              + */ + private static final int PAD_LIMIT = 8192; + + /** + *

              {@code StringUtils} instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * {@code StringUtils.trim(" foo ");}.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public StringUtils() { + super(); + } + + // Empty checks + //----------------------------------------------------------------------- + /** + *

              Checks if a CharSequence is empty ("") or null.

              + * + *
              +     * StringUtils.isEmpty(null)      = true
              +     * StringUtils.isEmpty("")        = true
              +     * StringUtils.isEmpty(" ")       = false
              +     * StringUtils.isEmpty("bob")     = false
              +     * StringUtils.isEmpty("  bob  ") = false
              +     * 
              + * + *

              NOTE: This method changed in Lang version 2.0. + * It no longer trims the CharSequence. + * That functionality is available in isBlank().

              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is empty or null + * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) + */ + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } + + /** + *

              Checks if a CharSequence is not empty ("") and not null.

              + * + *
              +     * StringUtils.isNotEmpty(null)      = false
              +     * StringUtils.isNotEmpty("")        = false
              +     * StringUtils.isNotEmpty(" ")       = true
              +     * StringUtils.isNotEmpty("bob")     = true
              +     * StringUtils.isNotEmpty("  bob  ") = true
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is not empty and not null + * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) + */ + public static boolean isNotEmpty(final CharSequence cs) { + return !isEmpty(cs); + } + + /** + *

              Checks if any of the CharSequences are empty ("") or null.

              + * + *
              +     * StringUtils.isAnyEmpty(null)             = true
              +     * StringUtils.isAnyEmpty(null, "foo")      = true
              +     * StringUtils.isAnyEmpty("", "bar")        = true
              +     * StringUtils.isAnyEmpty("bob", "")        = true
              +     * StringUtils.isAnyEmpty("  bob  ", null)  = true
              +     * StringUtils.isAnyEmpty(" ", "bar")       = false
              +     * StringUtils.isAnyEmpty("foo", "bar")     = false
              +     * 
              + * + * @param css the CharSequences to check, may be null or empty + * @return {@code true} if any of the CharSequences are empty or null + * @since 3.2 + */ + public static boolean isAnyEmpty(final CharSequence... css) { + if (ArrayUtils.isEmpty(css)) { + return false; + } + for (final CharSequence cs : css){ + if (isEmpty(cs)) { + return true; + } + } + return false; + } + + /** + *

              Checks if none of the CharSequences are empty ("") or null.

              + * + *
              +     * StringUtils.isNoneEmpty(null)             = false
              +     * StringUtils.isNoneEmpty(null, "foo")      = false
              +     * StringUtils.isNoneEmpty("", "bar")        = false
              +     * StringUtils.isNoneEmpty("bob", "")        = false
              +     * StringUtils.isNoneEmpty("  bob  ", null)  = false
              +     * StringUtils.isNoneEmpty(new String[] {})  = false
              +     * StringUtils.isNoneEmpty(" ", "bar")       = true
              +     * StringUtils.isNoneEmpty("foo", "bar")     = true
              +     * 
              + * + * @param css the CharSequences to check, may be null or empty + * @return {@code true} if none of the CharSequences are empty or null + * @since 3.2 + */ + public static boolean isNoneEmpty(final CharSequence... css) { + return !isAnyEmpty(css); + } + + /** + *

              Checks if all of the CharSequences are empty ("") or null.

              + * + *
              +     * StringUtils.isAllEmpty(null)             = true
              +     * StringUtils.isAllEmpty(null, "")         = true
              +     * StringUtils.isAllEmpty(new String[] {})  = true
              +     * StringUtils.isAllEmpty(null, "foo")      = false
              +     * StringUtils.isAllEmpty("", "bar")        = false
              +     * StringUtils.isAllEmpty("bob", "")        = false
              +     * StringUtils.isAllEmpty("  bob  ", null)  = false
              +     * StringUtils.isAllEmpty(" ", "bar")       = false
              +     * StringUtils.isAllEmpty("foo", "bar")     = false
              +     * 
              + * + * @param css the CharSequences to check, may be null or empty + * @return {@code true} if all of the CharSequences are empty or null + * @since 3.6 + */ + public static boolean isAllEmpty(final CharSequence... css) { + if (ArrayUtils.isEmpty(css)) { + return true; + } + for (final CharSequence cs : css) { + if (isNotEmpty(cs)) { + return false; + } + } + return true; + } + + /** + *

              Checks if a CharSequence is empty (""), null or whitespace only.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.isBlank(null)      = true
              +     * StringUtils.isBlank("")        = true
              +     * StringUtils.isBlank(" ")       = true
              +     * StringUtils.isBlank("bob")     = false
              +     * StringUtils.isBlank("  bob  ") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is null, empty or whitespace only + * @since 2.0 + * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) + */ + public static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + /** + *

              Checks if a CharSequence is not empty (""), not null and not whitespace only.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.isNotBlank(null)      = false
              +     * StringUtils.isNotBlank("")        = false
              +     * StringUtils.isNotBlank(" ")       = false
              +     * StringUtils.isNotBlank("bob")     = true
              +     * StringUtils.isNotBlank("  bob  ") = true
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is + * not empty and not null and not whitespace only + * @since 2.0 + * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) + */ + public static boolean isNotBlank(final CharSequence cs) { + return !isBlank(cs); + } + + /** + *

              Checks if any of the CharSequences are empty ("") or null or whitespace only.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.isAnyBlank(null)             = true
              +     * StringUtils.isAnyBlank(null, "foo")      = true
              +     * StringUtils.isAnyBlank(null, null)       = true
              +     * StringUtils.isAnyBlank("", "bar")        = true
              +     * StringUtils.isAnyBlank("bob", "")        = true
              +     * StringUtils.isAnyBlank("  bob  ", null)  = true
              +     * StringUtils.isAnyBlank(" ", "bar")       = true
              +     * StringUtils.isAnyBlank(new String[] {})  = false
              +     * StringUtils.isAnyBlank("foo", "bar")     = false
              +     * 
              + * + * @param css the CharSequences to check, may be null or empty + * @return {@code true} if any of the CharSequences are empty or null or whitespace only + * @since 3.2 + */ + public static boolean isAnyBlank(final CharSequence... css) { + if (ArrayUtils.isEmpty(css)) { + return false; + } + for (final CharSequence cs : css){ + if (isBlank(cs)) { + return true; + } + } + return false; + } + + /** + *

              Checks if none of the CharSequences are empty (""), null or whitespace only.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.isNoneBlank(null)             = false
              +     * StringUtils.isNoneBlank(null, "foo")      = false
              +     * StringUtils.isNoneBlank(null, null)       = false
              +     * StringUtils.isNoneBlank("", "bar")        = false
              +     * StringUtils.isNoneBlank("bob", "")        = false
              +     * StringUtils.isNoneBlank("  bob  ", null)  = false
              +     * StringUtils.isNoneBlank(" ", "bar")       = false
              +     * StringUtils.isNoneBlank(new String[] {})  = false
              +     * StringUtils.isNoneBlank("foo", "bar")     = true
              +     * 
              + * + * @param css the CharSequences to check, may be null or empty + * @return {@code true} if none of the CharSequences are empty or null or whitespace only + * @since 3.2 + */ + public static boolean isNoneBlank(final CharSequence... css) { + return !isAnyBlank(css); + } + + /** + *

              Checks if all of the CharSequences are empty (""), null or whitespace only.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.isAllBlank(null)             = true
              +     * StringUtils.isAllBlank(null, "foo")      = false
              +     * StringUtils.isAllBlank(null, null)       = true
              +     * StringUtils.isAllBlank("", "bar")        = false
              +     * StringUtils.isAllBlank("bob", "")        = false
              +     * StringUtils.isAllBlank("  bob  ", null)  = false
              +     * StringUtils.isAllBlank(" ", "bar")       = false
              +     * StringUtils.isAllBlank("foo", "bar")     = false
              +     * StringUtils.isAllBlank(new String[] {})  = true
              +     * 
              + * + * @param css the CharSequences to check, may be null or empty + * @return {@code true} if all of the CharSequences are empty or null or whitespace only + * @since 3.6 + */ + public static boolean isAllBlank(final CharSequence... css) { + if (ArrayUtils.isEmpty(css)) { + return true; + } + for (final CharSequence cs : css) { + if (isNotBlank(cs)) { + return false; + } + } + return true; + } + + // Trim + //----------------------------------------------------------------------- + /** + *

              Removes control characters (char <= 32) from both + * ends of this String, handling {@code null} by returning + * {@code null}.

              + * + *

              The String is trimmed using {@link String#trim()}. + * Trim removes start and end characters <= 32. + * To strip whitespace use {@link #strip(String)}.

              + * + *

              To trim your choice of characters, use the + * {@link #strip(String, String)} methods.

              + * + *
              +     * StringUtils.trim(null)          = null
              +     * StringUtils.trim("")            = ""
              +     * StringUtils.trim("     ")       = ""
              +     * StringUtils.trim("abc")         = "abc"
              +     * StringUtils.trim("    abc    ") = "abc"
              +     * 
              + * + * @param str the String to be trimmed, may be null + * @return the trimmed string, {@code null} if null String input + */ + public static String trim(final String str) { + return str == null ? null : str.trim(); + } + + /** + *

              Removes control characters (char <= 32) from both + * ends of this String returning {@code null} if the String is + * empty ("") after the trim or if it is {@code null}. + * + *

              The String is trimmed using {@link String#trim()}. + * Trim removes start and end characters <= 32. + * To strip whitespace use {@link #stripToNull(String)}.

              + * + *
              +     * StringUtils.trimToNull(null)          = null
              +     * StringUtils.trimToNull("")            = null
              +     * StringUtils.trimToNull("     ")       = null
              +     * StringUtils.trimToNull("abc")         = "abc"
              +     * StringUtils.trimToNull("    abc    ") = "abc"
              +     * 
              + * + * @param str the String to be trimmed, may be null + * @return the trimmed String, + * {@code null} if only chars <= 32, empty or null String input + * @since 2.0 + */ + public static String trimToNull(final String str) { + final String ts = trim(str); + return isEmpty(ts) ? null : ts; + } + + /** + *

              Removes control characters (char <= 32) from both + * ends of this String returning an empty String ("") if the String + * is empty ("") after the trim or if it is {@code null}. + * + *

              The String is trimmed using {@link String#trim()}. + * Trim removes start and end characters <= 32. + * To strip whitespace use {@link #stripToEmpty(String)}.

              + * + *
              +     * StringUtils.trimToEmpty(null)          = ""
              +     * StringUtils.trimToEmpty("")            = ""
              +     * StringUtils.trimToEmpty("     ")       = ""
              +     * StringUtils.trimToEmpty("abc")         = "abc"
              +     * StringUtils.trimToEmpty("    abc    ") = "abc"
              +     * 
              + * + * @param str the String to be trimmed, may be null + * @return the trimmed String, or an empty String if {@code null} input + * @since 2.0 + */ + public static String trimToEmpty(final String str) { + return str == null ? EMPTY : str.trim(); + } + + /** + *

              Truncates a String. This will turn + * "Now is the time for all good men" into "Now is the time for".

              + * + *

              Specifically:

              + *
                + *
              • If {@code str} is less than {@code maxWidth} characters + * long, return it.
              • + *
              • Else truncate it to {@code substring(str, 0, maxWidth)}.
              • + *
              • If {@code maxWidth} is less than {@code 0}, throw an + * {@code IllegalArgumentException}.
              • + *
              • In no case will it return a String of length greater than + * {@code maxWidth}.
              • + *
              + * + *
              +     * StringUtils.truncate(null, 0)       = null
              +     * StringUtils.truncate(null, 2)       = null
              +     * StringUtils.truncate("", 4)         = ""
              +     * StringUtils.truncate("abcdefg", 4)  = "abcd"
              +     * StringUtils.truncate("abcdefg", 6)  = "abcdef"
              +     * StringUtils.truncate("abcdefg", 7)  = "abcdefg"
              +     * StringUtils.truncate("abcdefg", 8)  = "abcdefg"
              +     * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
              +     * 
              + * + * @param str the String to truncate, may be null + * @param maxWidth maximum length of result String, must be positive + * @return truncated String, {@code null} if null String input + * @since 3.5 + */ + public static String truncate(final String str, final int maxWidth) { + return truncate(str, 0, maxWidth); + } + + /** + *

              Truncates a String. This will turn + * "Now is the time for all good men" into "is the time for all".

              + * + *

              Works like {@code truncate(String, int)}, but allows you to specify + * a "left edge" offset. + * + *

              Specifically:

              + *
                + *
              • If {@code str} is less than {@code maxWidth} characters + * long, return it.
              • + *
              • Else truncate it to {@code substring(str, offset, maxWidth)}.
              • + *
              • If {@code maxWidth} is less than {@code 0}, throw an + * {@code IllegalArgumentException}.
              • + *
              • If {@code offset} is less than {@code 0}, throw an + * {@code IllegalArgumentException}.
              • + *
              • In no case will it return a String of length greater than + * {@code maxWidth}.
              • + *
              + * + *
              +     * StringUtils.truncate(null, 0, 0) = null
              +     * StringUtils.truncate(null, 2, 4) = null
              +     * StringUtils.truncate("", 0, 10) = ""
              +     * StringUtils.truncate("", 2, 10) = ""
              +     * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
              +     * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
              +     * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
              +     * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
              +     * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
              +     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij"
              +     * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno"
              +     * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
              +     * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
              +     * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
              +     * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
              +     * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
              +     * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
              +     * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
              +     * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
              +     * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
              +     * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
              +     * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
              +     * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
              +     * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
              +     * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
              +     * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
              +     * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
              +     * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
              +     * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
              +     * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
              +     * 
              + * + * @param str the String to check, may be null + * @param offset left edge of source String + * @param maxWidth maximum length of result String, must be positive + * @return truncated String, {@code null} if null String input + * @since 3.5 + */ + public static String truncate(final String str, final int offset, final int maxWidth) { + if (offset < 0) { + throw new IllegalArgumentException("offset cannot be negative"); + } + if (maxWidth < 0) { + throw new IllegalArgumentException("maxWith cannot be negative"); + } + if (str == null) { + return null; + } + if (offset > str.length()) { + return EMPTY; + } + if (str.length() > maxWidth) { + final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth; + return str.substring(offset, ix); + } + return str.substring(offset); + } + + // Stripping + //----------------------------------------------------------------------- + /** + *

              Strips whitespace from the start and end of a String.

              + * + *

              This is similar to {@link #trim(String)} but removes whitespace. + * Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.strip(null)     = null
              +     * StringUtils.strip("")       = ""
              +     * StringUtils.strip("   ")    = ""
              +     * StringUtils.strip("abc")    = "abc"
              +     * StringUtils.strip("  abc")  = "abc"
              +     * StringUtils.strip("abc  ")  = "abc"
              +     * StringUtils.strip(" abc ")  = "abc"
              +     * StringUtils.strip(" ab c ") = "ab c"
              +     * 
              + * + * @param str the String to remove whitespace from, may be null + * @return the stripped String, {@code null} if null String input + */ + public static String strip(final String str) { + return strip(str, null); + } + + /** + *

              Strips whitespace from the start and end of a String returning + * {@code null} if the String is empty ("") after the strip.

              + * + *

              This is similar to {@link #trimToNull(String)} but removes whitespace. + * Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.stripToNull(null)     = null
              +     * StringUtils.stripToNull("")       = null
              +     * StringUtils.stripToNull("   ")    = null
              +     * StringUtils.stripToNull("abc")    = "abc"
              +     * StringUtils.stripToNull("  abc")  = "abc"
              +     * StringUtils.stripToNull("abc  ")  = "abc"
              +     * StringUtils.stripToNull(" abc ")  = "abc"
              +     * StringUtils.stripToNull(" ab c ") = "ab c"
              +     * 
              + * + * @param str the String to be stripped, may be null + * @return the stripped String, + * {@code null} if whitespace, empty or null String input + * @since 2.0 + */ + public static String stripToNull(String str) { + if (str == null) { + return null; + } + str = strip(str, null); + return str.isEmpty() ? null : str; + } + + /** + *

              Strips whitespace from the start and end of a String returning + * an empty String if {@code null} input.

              + * + *

              This is similar to {@link #trimToEmpty(String)} but removes whitespace. + * Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.stripToEmpty(null)     = ""
              +     * StringUtils.stripToEmpty("")       = ""
              +     * StringUtils.stripToEmpty("   ")    = ""
              +     * StringUtils.stripToEmpty("abc")    = "abc"
              +     * StringUtils.stripToEmpty("  abc")  = "abc"
              +     * StringUtils.stripToEmpty("abc  ")  = "abc"
              +     * StringUtils.stripToEmpty(" abc ")  = "abc"
              +     * StringUtils.stripToEmpty(" ab c ") = "ab c"
              +     * 
              + * + * @param str the String to be stripped, may be null + * @return the trimmed String, or an empty String if {@code null} input + * @since 2.0 + */ + public static String stripToEmpty(final String str) { + return str == null ? EMPTY : strip(str, null); + } + + /** + *

              Strips any of a set of characters from the start and end of a String. + * This is similar to {@link String#trim()} but allows the characters + * to be stripped to be controlled.

              + * + *

              A {@code null} input String returns {@code null}. + * An empty string ("") input returns the empty string.

              + * + *

              If the stripChars String is {@code null}, whitespace is + * stripped as defined by {@link Character#isWhitespace(char)}. + * Alternatively use {@link #strip(String)}.

              + * + *
              +     * StringUtils.strip(null, *)          = null
              +     * StringUtils.strip("", *)            = ""
              +     * StringUtils.strip("abc", null)      = "abc"
              +     * StringUtils.strip("  abc", null)    = "abc"
              +     * StringUtils.strip("abc  ", null)    = "abc"
              +     * StringUtils.strip(" abc ", null)    = "abc"
              +     * StringUtils.strip("  abcyx", "xyz") = "  abc"
              +     * 
              + * + * @param str the String to remove characters from, may be null + * @param stripChars the characters to remove, null treated as whitespace + * @return the stripped String, {@code null} if null String input + */ + public static String strip(String str, final String stripChars) { + if (isEmpty(str)) { + return str; + } + str = stripStart(str, stripChars); + return stripEnd(str, stripChars); + } + + /** + *

              Strips any of a set of characters from the start of a String.

              + * + *

              A {@code null} input String returns {@code null}. + * An empty string ("") input returns the empty string.

              + * + *

              If the stripChars String is {@code null}, whitespace is + * stripped as defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.stripStart(null, *)          = null
              +     * StringUtils.stripStart("", *)            = ""
              +     * StringUtils.stripStart("abc", "")        = "abc"
              +     * StringUtils.stripStart("abc", null)      = "abc"
              +     * StringUtils.stripStart("  abc", null)    = "abc"
              +     * StringUtils.stripStart("abc  ", null)    = "abc  "
              +     * StringUtils.stripStart(" abc ", null)    = "abc "
              +     * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
              +     * 
              + * + * @param str the String to remove characters from, may be null + * @param stripChars the characters to remove, null treated as whitespace + * @return the stripped String, {@code null} if null String input + */ + public static String stripStart(final String str, final String stripChars) { + int strLen; + if (str == null || (strLen = str.length()) == 0) { + return str; + } + int start = 0; + if (stripChars == null) { + while (start != strLen && Character.isWhitespace(str.charAt(start))) { + start++; + } + } else if (stripChars.isEmpty()) { + return str; + } else { + while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) { + start++; + } + } + return str.substring(start); + } + + /** + *

              Strips any of a set of characters from the end of a String.

              + * + *

              A {@code null} input String returns {@code null}. + * An empty string ("") input returns the empty string.

              + * + *

              If the stripChars String is {@code null}, whitespace is + * stripped as defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.stripEnd(null, *)          = null
              +     * StringUtils.stripEnd("", *)            = ""
              +     * StringUtils.stripEnd("abc", "")        = "abc"
              +     * StringUtils.stripEnd("abc", null)      = "abc"
              +     * StringUtils.stripEnd("  abc", null)    = "  abc"
              +     * StringUtils.stripEnd("abc  ", null)    = "abc"
              +     * StringUtils.stripEnd(" abc ", null)    = " abc"
              +     * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
              +     * StringUtils.stripEnd("120.00", ".0")   = "12"
              +     * 
              + * + * @param str the String to remove characters from, may be null + * @param stripChars the set of characters to remove, null treated as whitespace + * @return the stripped String, {@code null} if null String input + */ + public static String stripEnd(final String str, final String stripChars) { + int end; + if (str == null || (end = str.length()) == 0) { + return str; + } + + if (stripChars == null) { + while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { + end--; + } + } else if (stripChars.isEmpty()) { + return str; + } else { + while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { + end--; + } + } + return str.substring(0, end); + } + + // StripAll + //----------------------------------------------------------------------- + /** + *

              Strips whitespace from the start and end of every String in an array. + * Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *

              A new array is returned each time, except for length zero. + * A {@code null} array will return {@code null}. + * An empty array will return itself. + * A {@code null} array entry will be ignored.

              + * + *
              +     * StringUtils.stripAll(null)             = null
              +     * StringUtils.stripAll([])               = []
              +     * StringUtils.stripAll(["abc", "  abc"]) = ["abc", "abc"]
              +     * StringUtils.stripAll(["abc  ", null])  = ["abc", null]
              +     * 
              + * + * @param strs the array to remove whitespace from, may be null + * @return the stripped Strings, {@code null} if null array input + */ + public static String[] stripAll(final String... strs) { + return stripAll(strs, null); + } + + /** + *

              Strips any of a set of characters from the start and end of every + * String in an array.

              + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *

              A new array is returned each time, except for length zero. + * A {@code null} array will return {@code null}. + * An empty array will return itself. + * A {@code null} array entry will be ignored. + * A {@code null} stripChars will strip whitespace as defined by + * {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.stripAll(null, *)                = null
              +     * StringUtils.stripAll([], *)                  = []
              +     * StringUtils.stripAll(["abc", "  abc"], null) = ["abc", "abc"]
              +     * StringUtils.stripAll(["abc  ", null], null)  = ["abc", null]
              +     * StringUtils.stripAll(["abc  ", null], "yz")  = ["abc  ", null]
              +     * StringUtils.stripAll(["yabcz", null], "yz")  = ["abc", null]
              +     * 
              + * + * @param strs the array to remove characters from, may be null + * @param stripChars the characters to remove, null treated as whitespace + * @return the stripped Strings, {@code null} if null array input + */ + public static String[] stripAll(final String[] strs, final String stripChars) { + int strsLen; + if (strs == null || (strsLen = strs.length) == 0) { + return strs; + } + final String[] newArr = new String[strsLen]; + for (int i = 0; i < strsLen; i++) { + newArr[i] = strip(strs[i], stripChars); + } + return newArr; + } + + /** + *

              Removes diacritics (~= accents) from a string. The case will not be altered.

              + *

              For instance, 'à' will be replaced by 'a'.

              + *

              Note that ligatures will be left as is.

              + * + *
              +     * StringUtils.stripAccents(null)                = null
              +     * StringUtils.stripAccents("")                  = ""
              +     * StringUtils.stripAccents("control")           = "control"
              +     * StringUtils.stripAccents("éclair")     = "eclair"
              +     * 
              + * + * @param input String to be stripped + * @return input text with diacritics removed + * + * @since 3.0 + */ + // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907). + public static String stripAccents(final String input) { + if(input == null) { + return null; + } + final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$ + final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD)); + convertRemainingAccentCharacters(decomposed); + // Note that this doesn't correctly remove ligatures... + return pattern.matcher(decomposed).replaceAll(StringUtils.EMPTY); + } + + private static void convertRemainingAccentCharacters(final StringBuilder decomposed) { + for (int i = 0; i < decomposed.length(); i++) { + if (decomposed.charAt(i) == '\u0141') { + decomposed.deleteCharAt(i); + decomposed.insert(i, 'L'); + } else if (decomposed.charAt(i) == '\u0142') { + decomposed.deleteCharAt(i); + decomposed.insert(i, 'l'); + } + } + } + + // Equals + //----------------------------------------------------------------------- + /** + *

              Compares two CharSequences, returning {@code true} if they represent + * equal sequences of characters.

              + * + *

              {@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case sensitive.

              + * + *
              +     * StringUtils.equals(null, null)   = true
              +     * StringUtils.equals(null, "abc")  = false
              +     * StringUtils.equals("abc", null)  = false
              +     * StringUtils.equals("abc", "abc") = true
              +     * StringUtils.equals("abc", "ABC") = false
              +     * 
              + * + * @see Object#equals(Object) + * @param cs1 the first CharSequence, may be {@code null} + * @param cs2 the second CharSequence, may be {@code null} + * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null} + * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence) + */ + public static boolean equals(final CharSequence cs1, final CharSequence cs2) { + if (cs1 == cs2) { + return true; + } + if (cs1 == null || cs2 == null) { + return false; + } + if (cs1.length() != cs2.length()) { + return false; + } + if (cs1 instanceof String && cs2 instanceof String) { + return cs1.equals(cs2); + } + return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length()); + } + + /** + *

              Compares two CharSequences, returning {@code true} if they represent + * equal sequences of characters, ignoring case.

              + * + *

              {@code null}s are handled without exceptions. Two {@code null} + * references are considered equal. Comparison is case insensitive.

              + * + *
              +     * StringUtils.equalsIgnoreCase(null, null)   = true
              +     * StringUtils.equalsIgnoreCase(null, "abc")  = false
              +     * StringUtils.equalsIgnoreCase("abc", null)  = false
              +     * StringUtils.equalsIgnoreCase("abc", "abc") = true
              +     * StringUtils.equalsIgnoreCase("abc", "ABC") = true
              +     * 
              + * + * @param str1 the first CharSequence, may be null + * @param str2 the second CharSequence, may be null + * @return {@code true} if the CharSequence are equal, case insensitive, or + * both {@code null} + * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence) + */ + public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) { + if (str1 == null || str2 == null) { + return str1 == str2; + } else if (str1 == str2) { + return true; + } else if (str1.length() != str2.length()) { + return false; + } else { + return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length()); + } + } + + // Compare + //----------------------------------------------------------------------- + /** + *

              Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :

              + *
                + *
              • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
              • + *
              • {@code int < 0}, if {@code str1} is less than {@code str2}
              • + *
              • {@code int > 0}, if {@code str1} is greater than {@code str2}
              • + *
              + * + *

              This is a {@code null} safe version of :

              + *
              str1.compareTo(str2)
              + * + *

              {@code null} value is considered less than non-{@code null} value. + * Two {@code null} references are considered equal.

              + * + *
              +     * StringUtils.compare(null, null)   = 0
              +     * StringUtils.compare(null , "a")   < 0
              +     * StringUtils.compare("a", null)    > 0
              +     * StringUtils.compare("abc", "abc") = 0
              +     * StringUtils.compare("a", "b")     < 0
              +     * StringUtils.compare("b", "a")     > 0
              +     * StringUtils.compare("a", "B")     > 0
              +     * StringUtils.compare("ab", "abc")  < 0
              +     * 
              + * + * @see #compare(String, String, boolean) + * @see String#compareTo(String) + * @param str1 the String to compare from + * @param str2 the String to compare to + * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} + * @since 3.5 + */ + public static int compare(final String str1, final String str2) { + return compare(str1, str2, true); + } + + /** + *

              Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :

              + *
                + *
              • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
              • + *
              • {@code int < 0}, if {@code str1} is less than {@code str2}
              • + *
              • {@code int > 0}, if {@code str1} is greater than {@code str2}
              • + *
              + * + *

              This is a {@code null} safe version of :

              + *
              str1.compareTo(str2)
              + * + *

              {@code null} inputs are handled according to the {@code nullIsLess} parameter. + * Two {@code null} references are considered equal.

              + * + *
              +     * StringUtils.compare(null, null, *)     = 0
              +     * StringUtils.compare(null , "a", true)  < 0
              +     * StringUtils.compare(null , "a", false) > 0
              +     * StringUtils.compare("a", null, true)   > 0
              +     * StringUtils.compare("a", null, false)  < 0
              +     * StringUtils.compare("abc", "abc", *)   = 0
              +     * StringUtils.compare("a", "b", *)       < 0
              +     * StringUtils.compare("b", "a", *)       > 0
              +     * StringUtils.compare("a", "B", *)       > 0
              +     * StringUtils.compare("ab", "abc", *)    < 0
              +     * 
              + * + * @see String#compareTo(String) + * @param str1 the String to compare from + * @param str2 the String to compare to + * @param nullIsLess whether consider {@code null} value less than non-{@code null} value + * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2} + * @since 3.5 + */ + public static int compare(final String str1, final String str2, final boolean nullIsLess) { + if (str1 == str2) { + return 0; + } + if (str1 == null) { + return nullIsLess ? -1 : 1; + } + if (str2 == null) { + return nullIsLess ? 1 : - 1; + } + return str1.compareTo(str2); + } + + /** + *

              Compare two Strings lexicographically, ignoring case differences, + * as per {@link String#compareToIgnoreCase(String)}, returning :

              + *
                + *
              • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
              • + *
              • {@code int < 0}, if {@code str1} is less than {@code str2}
              • + *
              • {@code int > 0}, if {@code str1} is greater than {@code str2}
              • + *
              + * + *

              This is a {@code null} safe version of :

              + *
              str1.compareToIgnoreCase(str2)
              + * + *

              {@code null} value is considered less than non-{@code null} value. + * Two {@code null} references are considered equal. + * Comparison is case insensitive.

              + * + *
              +     * StringUtils.compareIgnoreCase(null, null)   = 0
              +     * StringUtils.compareIgnoreCase(null , "a")   < 0
              +     * StringUtils.compareIgnoreCase("a", null)    > 0
              +     * StringUtils.compareIgnoreCase("abc", "abc") = 0
              +     * StringUtils.compareIgnoreCase("abc", "ABC") = 0
              +     * StringUtils.compareIgnoreCase("a", "b")     < 0
              +     * StringUtils.compareIgnoreCase("b", "a")     > 0
              +     * StringUtils.compareIgnoreCase("a", "B")     < 0
              +     * StringUtils.compareIgnoreCase("A", "b")     < 0
              +     * StringUtils.compareIgnoreCase("ab", "ABC")  < 0
              +     * 
              + * + * @see #compareIgnoreCase(String, String, boolean) + * @see String#compareToIgnoreCase(String) + * @param str1 the String to compare from + * @param str2 the String to compare to + * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, + * ignoring case differences. + * @since 3.5 + */ + public static int compareIgnoreCase(final String str1, final String str2) { + return compareIgnoreCase(str1, str2, true); + } + + /** + *

              Compare two Strings lexicographically, ignoring case differences, + * as per {@link String#compareToIgnoreCase(String)}, returning :

              + *
                + *
              • {@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})
              • + *
              • {@code int < 0}, if {@code str1} is less than {@code str2}
              • + *
              • {@code int > 0}, if {@code str1} is greater than {@code str2}
              • + *
              + * + *

              This is a {@code null} safe version of :

              + *
              str1.compareToIgnoreCase(str2)
              + * + *

              {@code null} inputs are handled according to the {@code nullIsLess} parameter. + * Two {@code null} references are considered equal. + * Comparison is case insensitive.

              + * + *
              +     * StringUtils.compareIgnoreCase(null, null, *)     = 0
              +     * StringUtils.compareIgnoreCase(null , "a", true)  < 0
              +     * StringUtils.compareIgnoreCase(null , "a", false) > 0
              +     * StringUtils.compareIgnoreCase("a", null, true)   > 0
              +     * StringUtils.compareIgnoreCase("a", null, false)  < 0
              +     * StringUtils.compareIgnoreCase("abc", "abc", *)   = 0
              +     * StringUtils.compareIgnoreCase("abc", "ABC", *)   = 0
              +     * StringUtils.compareIgnoreCase("a", "b", *)       < 0
              +     * StringUtils.compareIgnoreCase("b", "a", *)       > 0
              +     * StringUtils.compareIgnoreCase("a", "B", *)       < 0
              +     * StringUtils.compareIgnoreCase("A", "b", *)       < 0
              +     * StringUtils.compareIgnoreCase("ab", "abc", *)    < 0
              +     * 
              + * + * @see String#compareToIgnoreCase(String) + * @param str1 the String to compare from + * @param str2 the String to compare to + * @param nullIsLess whether consider {@code null} value less than non-{@code null} value + * @return < 0, 0, > 0, if {@code str1} is respectively less, equal ou greater than {@code str2}, + * ignoring case differences. + * @since 3.5 + */ + public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { + if (str1 == str2) { + return 0; + } + if (str1 == null) { + return nullIsLess ? -1 : 1; + } + if (str2 == null) { + return nullIsLess ? 1 : - 1; + } + return str1.compareToIgnoreCase(str2); + } + + /** + *

              Compares given string to a CharSequences vararg of searchStrings, + * returning {@code true} if the string is equal to any of the searchStrings.

              + * + *
              +     * StringUtils.equalsAny(null, (CharSequence[]) null) = false
              +     * StringUtils.equalsAny(null, null, null)    = true
              +     * StringUtils.equalsAny(null, "abc", "def")  = false
              +     * StringUtils.equalsAny("abc", null, "def")  = false
              +     * StringUtils.equalsAny("abc", "abc", "def") = true
              +     * StringUtils.equalsAny("abc", "ABC", "DEF") = false
              +     * 
              + * + * @param string to compare, may be {@code null}. + * @param searchStrings a vararg of strings, may be {@code null}. + * @return {@code true} if the string is equal (case-sensitive) to any other element of searchStrings; + * {@code false} if searchStrings is null or contains no matches. + * @since 3.5 + */ + public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { + if (ArrayUtils.isNotEmpty(searchStrings)) { + for (final CharSequence next : searchStrings) { + if (equals(string, next)) { + return true; + } + } + } + return false; + } + + + /** + *

              Compares given string to a CharSequences vararg of searchStrings, + * returning {@code true} if the string is equal to any of the searchStrings, ignoring case.

              + * + *
              +     * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
              +     * StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
              +     * StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
              +     * StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
              +     * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
              +     * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
              +     * 
              + * + * @param string to compare, may be {@code null}. + * @param searchStrings a vararg of strings, may be {@code null}. + * @return {@code true} if the string is equal (case-insensitive) to any other element of searchStrings; + * {@code false} if searchStrings is null or contains no matches. + * @since 3.5 + */ + public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) { + if (ArrayUtils.isNotEmpty(searchStrings)) { + for (final CharSequence next : searchStrings) { + if (equalsIgnoreCase(string, next)) { + return true; + } + } + } + return false; + } + + // IndexOf + //----------------------------------------------------------------------- + /** + * Returns the index within seq of the first occurrence of + * the specified character. If a character with value + * searchChar occurs in the character sequence represented by + * seq CharSequence object, then the index (in Unicode + * code units) of the first such occurrence is returned. For + * values of searchChar in the range from 0 to 0xFFFF + * (inclusive), this is the smallest value k such that: + *
              +     * this.charAt(k) == searchChar
              +     * 
              + * is true. For other values of searchChar, it is the + * smallest value k such that: + *
              +     * this.codePointAt(k) == searchChar
              +     * 
              + * is true. In either case, if no such character occurs in seq, + * then {@code INDEX_NOT_FOUND (-1)} is returned. + * + *

              Furthermore, a {@code null} or empty ("") CharSequence will + * return {@code INDEX_NOT_FOUND (-1)}.

              + * + *
              +     * StringUtils.indexOf(null, *)         = -1
              +     * StringUtils.indexOf("", *)           = -1
              +     * StringUtils.indexOf("aabaabaa", 'a') = 0
              +     * StringUtils.indexOf("aabaabaa", 'b') = 2
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchChar the character to find + * @return the first index of the search character, + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int) + * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like String + */ + public static int indexOf(final CharSequence seq, final int searchChar) { + if (isEmpty(seq)) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.indexOf(seq, searchChar, 0); + } + + /** + * + * Returns the index within seq of the first occurrence of the + * specified character, starting the search at the specified index. + *

              + * If a character with value searchChar occurs in the + * character sequence represented by the seq CharSequence + * object at an index no smaller than startPos, then + * the index of the first such occurrence is returned. For values + * of searchChar in the range from 0 to 0xFFFF (inclusive), + * this is the smallest value k such that: + *

              +     * (this.charAt(k) == searchChar) && (k >= startPos)
              +     * 
              + * is true. For other values of searchChar, it is the + * smallest value k such that: + *
              +     * (this.codePointAt(k) == searchChar) && (k >= startPos)
              +     * 
              + * is true. In either case, if no such character occurs in seq + * at or after position startPos, then + * -1 is returned. + * + *

              + * There is no restriction on the value of startPos. If it + * is negative, it has the same effect as if it were zero: this entire + * string may be searched. If it is greater than the length of this + * string, it has the same effect as if it were equal to the length of + * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a + * {@code null} or empty ("") CharSequence will + * return {@code (INDEX_NOT_FOUND) -1}. + * + *

              All indices are specified in char values + * (Unicode code units). + * + *

              +     * StringUtils.indexOf(null, *, *)          = -1
              +     * StringUtils.indexOf("", *, *)            = -1
              +     * StringUtils.indexOf("aabaabaa", 'b', 0)  = 2
              +     * StringUtils.indexOf("aabaabaa", 'b', 3)  = 5
              +     * StringUtils.indexOf("aabaabaa", 'b', 9)  = -1
              +     * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchChar the character to find + * @param startPos the start position, negative treated as zero + * @return the first index of the search character (always ≥ startPos), + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int) + * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like String + */ + public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { + if (isEmpty(seq)) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.indexOf(seq, searchChar, startPos); + } + + /** + *

              Finds the first index within a CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String, int)} if possible.

              + * + *

              A {@code null} CharSequence will return {@code -1}.

              + * + *
              +     * StringUtils.indexOf(null, *)          = -1
              +     * StringUtils.indexOf(*, null)          = -1
              +     * StringUtils.indexOf("", "")           = 0
              +     * StringUtils.indexOf("", *)            = -1 (except when * = "")
              +     * StringUtils.indexOf("aabaabaa", "a")  = 0
              +     * StringUtils.indexOf("aabaabaa", "b")  = 2
              +     * StringUtils.indexOf("aabaabaa", "ab") = 1
              +     * StringUtils.indexOf("aabaabaa", "")   = 0
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchSeq the CharSequence to find, may be null + * @return the first index of the search CharSequence, + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence) + */ + public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { + if (seq == null || searchSeq == null) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.indexOf(seq, searchSeq, 0); + } + + /** + *

              Finds the first index within a CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String, int)} if possible.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A negative start position is treated as zero. + * An empty ("") search CharSequence always matches. + * A start position greater than the string length only matches + * an empty search CharSequence.

              + * + *
              +     * StringUtils.indexOf(null, *, *)          = -1
              +     * StringUtils.indexOf(*, null, *)          = -1
              +     * StringUtils.indexOf("", "", 0)           = 0
              +     * StringUtils.indexOf("", *, 0)            = -1 (except when * = "")
              +     * StringUtils.indexOf("aabaabaa", "a", 0)  = 0
              +     * StringUtils.indexOf("aabaabaa", "b", 0)  = 2
              +     * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
              +     * StringUtils.indexOf("aabaabaa", "b", 3)  = 5
              +     * StringUtils.indexOf("aabaabaa", "b", 9)  = -1
              +     * StringUtils.indexOf("aabaabaa", "b", -1) = 2
              +     * StringUtils.indexOf("aabaabaa", "", 2)   = 2
              +     * StringUtils.indexOf("abc", "", 9)        = 3
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchSeq the CharSequence to find, may be null + * @param startPos the start position, negative treated as zero + * @return the first index of the search CharSequence (always ≥ startPos), + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int) + */ + public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { + if (seq == null || searchSeq == null) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.indexOf(seq, searchSeq, startPos); + } + + /** + *

              Finds the n-th index within a CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String)} if possible.

              + *

              Note: The code starts looking for a match at the start of the target, + * incrementing the starting index by one after each successful match + * (unless {@code searchStr} is an empty string in which case the position + * is never incremented and {@code 0} is returned immediately). + * This means that matches may overlap.

              + *

              A {@code null} CharSequence will return {@code -1}.

              + * + *
              +     * StringUtils.ordinalIndexOf(null, *, *)          = -1
              +     * StringUtils.ordinalIndexOf(*, null, *)          = -1
              +     * StringUtils.ordinalIndexOf("", "", *)           = 0
              +     * StringUtils.ordinalIndexOf("aabaabaa", "a", 1)  = 0
              +     * StringUtils.ordinalIndexOf("aabaabaa", "a", 2)  = 1
              +     * StringUtils.ordinalIndexOf("aabaabaa", "b", 1)  = 2
              +     * StringUtils.ordinalIndexOf("aabaabaa", "b", 2)  = 5
              +     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
              +     * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
              +     * StringUtils.ordinalIndexOf("aabaabaa", "", 1)   = 0
              +     * StringUtils.ordinalIndexOf("aabaabaa", "", 2)   = 0
              +     * 
              + * + *

              Matches may overlap:

              + *
              +     * StringUtils.ordinalIndexOf("ababab","aba", 1)   = 0
              +     * StringUtils.ordinalIndexOf("ababab","aba", 2)   = 2
              +     * StringUtils.ordinalIndexOf("ababab","aba", 3)   = -1
              +     *
              +     * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
              +     * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
              +     * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
              +     * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
              +     * 
              + * + *

              Note that 'head(CharSequence str, int n)' may be implemented as:

              + * + *
              +     *   str.substring(0, lastOrdinalIndexOf(str, "\n", n))
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param ordinal the n-th {@code searchStr} to find + * @return the n-th index of the search CharSequence, + * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input + * @since 2.1 + * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int) + */ + public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { + return ordinalIndexOf(str, searchStr, ordinal, false); + } + + /** + *

              Finds the n-th index within a String, handling {@code null}. + * This method uses {@link String#indexOf(String)} if possible.

              + *

              Note that matches may overlap

              + * + *

              A {@code null} CharSequence will return {@code -1}.

              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed. + * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf() + * @return the n-th index of the search CharSequence, + * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input + */ + // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int) + private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) { + if (str == null || searchStr == null || ordinal <= 0) { + return INDEX_NOT_FOUND; + } + if (searchStr.length() == 0) { + return lastIndex ? str.length() : 0; + } + int found = 0; + // set the initial index beyond the end of the string + // this is to allow for the initial index decrement/increment + int index = lastIndex ? str.length() : INDEX_NOT_FOUND; + do { + if (lastIndex) { + index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string + } else { + index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string + } + if (index < 0) { + return index; + } + found++; + } while (found < ordinal); + return index; + } + + /** + *

              Case in-sensitive find of the first index within a CharSequence.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A negative start position is treated as zero. + * An empty ("") search CharSequence always matches. + * A start position greater than the string length only matches + * an empty search CharSequence.

              + * + *
              +     * StringUtils.indexOfIgnoreCase(null, *)          = -1
              +     * StringUtils.indexOfIgnoreCase(*, null)          = -1
              +     * StringUtils.indexOfIgnoreCase("", "")           = 0
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "a")  = 0
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "b")  = 2
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @return the first index of the search CharSequence, + * -1 if no match or {@code null} string input + * @since 2.5 + * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence) + */ + public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { + return indexOfIgnoreCase(str, searchStr, 0); + } + + /** + *

              Case in-sensitive find of the first index within a CharSequence + * from the specified position.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A negative start position is treated as zero. + * An empty ("") search CharSequence always matches. + * A start position greater than the string length only matches + * an empty search CharSequence.

              + * + *
              +     * StringUtils.indexOfIgnoreCase(null, *, *)          = -1
              +     * StringUtils.indexOfIgnoreCase(*, null, *)          = -1
              +     * StringUtils.indexOfIgnoreCase("", "", 0)           = 0
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0)  = 0
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0)  = 2
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3)  = 5
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9)  = -1
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
              +     * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2)   = 2
              +     * StringUtils.indexOfIgnoreCase("abc", "", 9)        = -1
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param startPos the start position, negative treated as zero + * @return the first index of the search CharSequence (always ≥ startPos), + * -1 if no match or {@code null} string input + * @since 2.5 + * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int) + */ + public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { + if (str == null || searchStr == null) { + return INDEX_NOT_FOUND; + } + if (startPos < 0) { + startPos = 0; + } + final int endLimit = str.length() - searchStr.length() + 1; + if (startPos > endLimit) { + return INDEX_NOT_FOUND; + } + if (searchStr.length() == 0) { + return startPos; + } + for (int i = startPos; i < endLimit; i++) { + if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + // LastIndexOf + //----------------------------------------------------------------------- + /** + * Returns the index within seq of the last occurrence of + * the specified character. For values of searchChar in the + * range from 0 to 0xFFFF (inclusive), the index (in Unicode code + * units) returned is the largest value k such that: + *
              +     * this.charAt(k) == searchChar
              +     * 
              + * is true. For other values of searchChar, it is the + * largest value k such that: + *
              +     * this.codePointAt(k) == searchChar
              +     * 
              + * is true. In either case, if no such character occurs in this + * string, then -1 is returned. Furthermore, a {@code null} or empty ("") + * CharSequence will return {@code -1}. The + * seq CharSequence object is searched backwards + * starting at the last character. + * + *
              +     * StringUtils.lastIndexOf(null, *)         = -1
              +     * StringUtils.lastIndexOf("", *)           = -1
              +     * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
              +     * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchChar the character to find + * @return the last index of the search character, + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int) + * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like String + */ + public static int lastIndexOf(final CharSequence seq, final int searchChar) { + if (isEmpty(seq)) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length()); + } + + /** + * Returns the index within seq of the last occurrence of + * the specified character, searching backward starting at the + * specified index. For values of searchChar in the range + * from 0 to 0xFFFF (inclusive), the index returned is the largest + * value k such that: + *
              +     * (this.charAt(k) == searchChar) && (k <= startPos)
              +     * 
              + * is true. For other values of searchChar, it is the + * largest value k such that: + *
              +     * (this.codePointAt(k) == searchChar) && (k <= startPos)
              +     * 
              + * is true. In either case, if no such character occurs in seq + * at or before position startPos, then + * -1 is returned. Furthermore, a {@code null} or empty ("") + * CharSequence will return {@code -1}. A start position greater + * than the string length searches the whole string. + * The search starts at the startPos and works backwards; + * matches starting after the start position are ignored. + * + *

              All indices are specified in char values + * (Unicode code units). + * + *

              +     * StringUtils.lastIndexOf(null, *, *)          = -1
              +     * StringUtils.lastIndexOf("", *,  *)           = -1
              +     * StringUtils.lastIndexOf("aabaabaa", 'b', 8)  = 5
              +     * StringUtils.lastIndexOf("aabaabaa", 'b', 4)  = 2
              +     * StringUtils.lastIndexOf("aabaabaa", 'b', 0)  = -1
              +     * StringUtils.lastIndexOf("aabaabaa", 'b', 9)  = 5
              +     * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
              +     * StringUtils.lastIndexOf("aabaabaa", 'a', 0)  = 0
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchChar the character to find + * @param startPos the start position + * @return the last index of the search character (always ≤ startPos), + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int) + */ + public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { + if (isEmpty(seq)) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos); + } + + /** + *

              Finds the last index within a CharSequence, handling {@code null}. + * This method uses {@link String#lastIndexOf(String)} if possible.

              + * + *

              A {@code null} CharSequence will return {@code -1}.

              + * + *
              +     * StringUtils.lastIndexOf(null, *)          = -1
              +     * StringUtils.lastIndexOf(*, null)          = -1
              +     * StringUtils.lastIndexOf("", "")           = 0
              +     * StringUtils.lastIndexOf("aabaabaa", "a")  = 7
              +     * StringUtils.lastIndexOf("aabaabaa", "b")  = 5
              +     * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
              +     * StringUtils.lastIndexOf("aabaabaa", "")   = 8
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchSeq the CharSequence to find, may be null + * @return the last index of the search String, + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence) + */ + public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { + if (seq == null || searchSeq == null) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length()); + } + + /** + *

              Finds the n-th last index within a String, handling {@code null}. + * This method uses {@link String#lastIndexOf(String)}.

              + * + *

              A {@code null} String will return {@code -1}.

              + * + *
              +     * StringUtils.lastOrdinalIndexOf(null, *, *)          = -1
              +     * StringUtils.lastOrdinalIndexOf(*, null, *)          = -1
              +     * StringUtils.lastOrdinalIndexOf("", "", *)           = 0
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1)  = 7
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2)  = 6
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1)  = 5
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2)  = 2
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1)   = 8
              +     * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2)   = 8
              +     * 
              + * + *

              Note that 'tail(CharSequence str, int n)' may be implemented as:

              + * + *
              +     *   str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param ordinal the n-th last {@code searchStr} to find + * @return the n-th last index of the search CharSequence, + * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input + * @since 2.5 + * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int) + */ + public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { + return ordinalIndexOf(str, searchStr, ordinal, true); + } + + /** + *

              Finds the last index within a CharSequence, handling {@code null}. + * This method uses {@link String#lastIndexOf(String, int)} if possible.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A negative start position returns {@code -1}. + * An empty ("") search CharSequence always matches unless the start position is negative. + * A start position greater than the string length searches the whole string. + * The search starts at the startPos and works backwards; matches starting after the start + * position are ignored. + *

              + * + *
              +     * StringUtils.lastIndexOf(null, *, *)          = -1
              +     * StringUtils.lastIndexOf(*, null, *)          = -1
              +     * StringUtils.lastIndexOf("aabaabaa", "a", 8)  = 7
              +     * StringUtils.lastIndexOf("aabaabaa", "b", 8)  = 5
              +     * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
              +     * StringUtils.lastIndexOf("aabaabaa", "b", 9)  = 5
              +     * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
              +     * StringUtils.lastIndexOf("aabaabaa", "a", 0)  = 0
              +     * StringUtils.lastIndexOf("aabaabaa", "b", 0)  = -1
              +     * StringUtils.lastIndexOf("aabaabaa", "b", 1)  = -1
              +     * StringUtils.lastIndexOf("aabaabaa", "b", 2)  = 2
              +     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = -1
              +     * StringUtils.lastIndexOf("aabaabaa", "ba", 2)  = 2
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchSeq the CharSequence to find, may be null + * @param startPos the start position, negative treated as zero + * @return the last index of the search CharSequence (always ≤ startPos), + * -1 if no match or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int) + */ + public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { + if (seq == null || searchSeq == null) { + return INDEX_NOT_FOUND; + } + return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos); + } + + /** + *

              Case in-sensitive find of the last index within a CharSequence.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A negative start position returns {@code -1}. + * An empty ("") search CharSequence always matches unless the start position is negative. + * A start position greater than the string length searches the whole string.

              + * + *
              +     * StringUtils.lastIndexOfIgnoreCase(null, *)          = -1
              +     * StringUtils.lastIndexOfIgnoreCase(*, null)          = -1
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A")  = 7
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B")  = 5
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @return the first index of the search CharSequence, + * -1 if no match or {@code null} string input + * @since 2.5 + * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence) + */ + public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { + if (str == null || searchStr == null) { + return INDEX_NOT_FOUND; + } + return lastIndexOfIgnoreCase(str, searchStr, str.length()); + } + + /** + *

              Case in-sensitive find of the last index within a CharSequence + * from the specified position.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A negative start position returns {@code -1}. + * An empty ("") search CharSequence always matches unless the start position is negative. + * A start position greater than the string length searches the whole string. + * The search starts at the startPos and works backwards; matches starting after the start + * position are ignored. + *

              + * + *
              +     * StringUtils.lastIndexOfIgnoreCase(null, *, *)          = -1
              +     * StringUtils.lastIndexOfIgnoreCase(*, null, *)          = -1
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8)  = 7
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8)  = 5
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9)  = 5
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0)  = 0
              +     * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0)  = -1
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @param startPos the start position + * @return the last index of the search CharSequence (always ≤ startPos), + * -1 if no match or {@code null} input + * @since 2.5 + * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int) + */ + public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { + if (str == null || searchStr == null) { + return INDEX_NOT_FOUND; + } + if (startPos > str.length() - searchStr.length()) { + startPos = str.length() - searchStr.length(); + } + if (startPos < 0) { + return INDEX_NOT_FOUND; + } + if (searchStr.length() == 0) { + return startPos; + } + + for (int i = startPos; i >= 0; i--) { + if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) { + return i; + } + } + return INDEX_NOT_FOUND; + } + + // Contains + //----------------------------------------------------------------------- + /** + *

              Checks if CharSequence contains a search character, handling {@code null}. + * This method uses {@link String#indexOf(int)} if possible.

              + * + *

              A {@code null} or empty ("") CharSequence will return {@code false}.

              + * + *
              +     * StringUtils.contains(null, *)    = false
              +     * StringUtils.contains("", *)      = false
              +     * StringUtils.contains("abc", 'a') = true
              +     * StringUtils.contains("abc", 'z') = false
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchChar the character to find + * @return true if the CharSequence contains the search character, + * false if not or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int) + */ + public static boolean contains(final CharSequence seq, final int searchChar) { + if (isEmpty(seq)) { + return false; + } + return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0; + } + + /** + *

              Checks if CharSequence contains a search CharSequence, handling {@code null}. + * This method uses {@link String#indexOf(String)} if possible.

              + * + *

              A {@code null} CharSequence will return {@code false}.

              + * + *
              +     * StringUtils.contains(null, *)     = false
              +     * StringUtils.contains(*, null)     = false
              +     * StringUtils.contains("", "")      = true
              +     * StringUtils.contains("abc", "")   = true
              +     * StringUtils.contains("abc", "a")  = true
              +     * StringUtils.contains("abc", "z")  = false
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchSeq the CharSequence to find, may be null + * @return true if the CharSequence contains the search CharSequence, + * false if not or {@code null} string input + * @since 2.0 + * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence) + */ + public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { + if (seq == null || searchSeq == null) { + return false; + } + return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0; + } + + /** + *

              Checks if CharSequence contains a search CharSequence irrespective of case, + * handling {@code null}. Case-insensitivity is defined as by + * {@link String#equalsIgnoreCase(String)}. + * + *

              A {@code null} CharSequence will return {@code false}.

              + * + *
              +     * StringUtils.containsIgnoreCase(null, *) = false
              +     * StringUtils.containsIgnoreCase(*, null) = false
              +     * StringUtils.containsIgnoreCase("", "") = true
              +     * StringUtils.containsIgnoreCase("abc", "") = true
              +     * StringUtils.containsIgnoreCase("abc", "a") = true
              +     * StringUtils.containsIgnoreCase("abc", "z") = false
              +     * StringUtils.containsIgnoreCase("abc", "A") = true
              +     * StringUtils.containsIgnoreCase("abc", "Z") = false
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStr the CharSequence to find, may be null + * @return true if the CharSequence contains the search CharSequence irrespective of + * case or false if not or {@code null} string input + * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence) + */ + public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { + if (str == null || searchStr == null) { + return false; + } + final int len = searchStr.length(); + final int max = str.length() - len; + for (int i = 0; i <= max; i++) { + if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) { + return true; + } + } + return false; + } + + /** + *

              Check whether the given CharSequence contains any whitespace characters.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + * @param seq the CharSequence to check (may be {@code null}) + * @return {@code true} if the CharSequence is not empty and + * contains at least 1 (breaking) whitespace character + * @since 3.0 + */ + // From org.springframework.util.StringUtils, under Apache License 2.0 + public static boolean containsWhitespace(final CharSequence seq) { + if (isEmpty(seq)) { + return false; + } + final int strLen = seq.length(); + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(seq.charAt(i))) { + return true; + } + } + return false; + } + + // IndexOfAny chars + //----------------------------------------------------------------------- + /** + *

              Search a CharSequence to find the first index of any + * character in the given set of characters.

              + * + *

              A {@code null} String will return {@code -1}. + * A {@code null} or zero length search array will return {@code -1}.

              + * + *
              +     * StringUtils.indexOfAny(null, *)                = -1
              +     * StringUtils.indexOfAny("", *)                  = -1
              +     * StringUtils.indexOfAny(*, null)                = -1
              +     * StringUtils.indexOfAny(*, [])                  = -1
              +     * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
              +     * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
              +     * StringUtils.indexOfAny("aba", ['z'])           = -1
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @param searchChars the chars to search for, may be null + * @return the index of any of the chars, -1 if no match or null input + * @since 2.0 + * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...) + */ + public static int indexOfAny(final CharSequence cs, final char... searchChars) { + if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { + return INDEX_NOT_FOUND; + } + final int csLen = cs.length(); + final int csLast = csLen - 1; + final int searchLen = searchChars.length; + final int searchLast = searchLen - 1; + for (int i = 0; i < csLen; i++) { + final char ch = cs.charAt(i); + for (int j = 0; j < searchLen; j++) { + if (searchChars[j] == ch) { + if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { + // ch is a supplementary character + if (searchChars[j + 1] == cs.charAt(i + 1)) { + return i; + } + } else { + return i; + } + } + } + } + return INDEX_NOT_FOUND; + } + + /** + *

              Search a CharSequence to find the first index of any + * character in the given set of characters.

              + * + *

              A {@code null} String will return {@code -1}. + * A {@code null} search string will return {@code -1}.

              + * + *
              +     * StringUtils.indexOfAny(null, *)            = -1
              +     * StringUtils.indexOfAny("", *)              = -1
              +     * StringUtils.indexOfAny(*, null)            = -1
              +     * StringUtils.indexOfAny(*, "")              = -1
              +     * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
              +     * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
              +     * StringUtils.indexOfAny("aba","z")          = -1
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @param searchChars the chars to search for, may be null + * @return the index of any of the chars, -1 if no match or null input + * @since 2.0 + * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String) + */ + public static int indexOfAny(final CharSequence cs, final String searchChars) { + if (isEmpty(cs) || isEmpty(searchChars)) { + return INDEX_NOT_FOUND; + } + return indexOfAny(cs, searchChars.toCharArray()); + } + + // ContainsAny + //----------------------------------------------------------------------- + /** + *

              Checks if the CharSequence contains any character in the given + * set of characters.

              + * + *

              A {@code null} CharSequence will return {@code false}. + * A {@code null} or zero length search array will return {@code false}.

              + * + *
              +     * StringUtils.containsAny(null, *)                = false
              +     * StringUtils.containsAny("", *)                  = false
              +     * StringUtils.containsAny(*, null)                = false
              +     * StringUtils.containsAny(*, [])                  = false
              +     * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
              +     * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
              +     * StringUtils.containsAny("zzabyycdxx",['z','y']) = true
              +     * StringUtils.containsAny("aba", ['z'])           = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @param searchChars the chars to search for, may be null + * @return the {@code true} if any of the chars are found, + * {@code false} if no match or null input + * @since 2.4 + * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...) + */ + public static boolean containsAny(final CharSequence cs, final char... searchChars) { + if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { + return false; + } + final int csLength = cs.length(); + final int searchLength = searchChars.length; + final int csLast = csLength - 1; + final int searchLast = searchLength - 1; + for (int i = 0; i < csLength; i++) { + final char ch = cs.charAt(i); + for (int j = 0; j < searchLength; j++) { + if (searchChars[j] == ch) { + if (Character.isHighSurrogate(ch)) { + if (j == searchLast) { + // missing low surrogate, fine, like String.indexOf(String) + return true; + } + if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { + return true; + } + } else { + // ch is in the Basic Multilingual Plane + return true; + } + } + } + } + return false; + } + + /** + *

              + * Checks if the CharSequence contains any character in the given set of characters. + *

              + * + *

              + * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return + * {@code false}. + *

              + * + *
              +     * StringUtils.containsAny(null, *)               = false
              +     * StringUtils.containsAny("", *)                 = false
              +     * StringUtils.containsAny(*, null)               = false
              +     * StringUtils.containsAny(*, "")                 = false
              +     * StringUtils.containsAny("zzabyycdxx", "za")    = true
              +     * StringUtils.containsAny("zzabyycdxx", "by")    = true
              +     * StringUtils.containsAny("zzabyycdxx", "zy")    = true
              +     * StringUtils.containsAny("zzabyycdxx", "\tx")   = true
              +     * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
              +     * StringUtils.containsAny("aba","z")             = false
              +     * 
              + * + * @param cs + * the CharSequence to check, may be null + * @param searchChars + * the chars to search for, may be null + * @return the {@code true} if any of the chars are found, {@code false} if no match or null input + * @since 2.4 + * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence) + */ + public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { + if (searchChars == null) { + return false; + } + return containsAny(cs, CharSequenceUtils.toCharArray(searchChars)); + } + + /** + *

              Checks if the CharSequence contains any of the CharSequences in the given array.

              + * + *

              + * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero + * length search array will return {@code false}. + *

              + * + *
              +     * StringUtils.containsAny(null, *)            = false
              +     * StringUtils.containsAny("", *)              = false
              +     * StringUtils.containsAny(*, null)            = false
              +     * StringUtils.containsAny(*, [])              = false
              +     * StringUtils.containsAny("abcd", "ab", null) = true
              +     * StringUtils.containsAny("abcd", "ab", "cd") = true
              +     * StringUtils.containsAny("abc", "d", "abc")  = true
              +     * 
              + * + * + * @param cs The CharSequence to check, may be null + * @param searchCharSequences The array of CharSequences to search for, may be null. + * Individual CharSequences may be null as well. + * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise + * @since 3.4 + */ + public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { + if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) { + return false; + } + for (final CharSequence searchCharSequence : searchCharSequences) { + if (contains(cs, searchCharSequence)) { + return true; + } + } + return false; + } + + // IndexOfAnyBut chars + //----------------------------------------------------------------------- + /** + *

              Searches a CharSequence to find the first index of any + * character not in the given set of characters.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A {@code null} or zero length search array will return {@code -1}.

              + * + *
              +     * StringUtils.indexOfAnyBut(null, *)                              = -1
              +     * StringUtils.indexOfAnyBut("", *)                                = -1
              +     * StringUtils.indexOfAnyBut(*, null)                              = -1
              +     * StringUtils.indexOfAnyBut(*, [])                                = -1
              +     * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
              +     * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
              +     * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
              +
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @param searchChars the chars to search for, may be null + * @return the index of any of the chars, -1 if no match or null input + * @since 2.0 + * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...) + */ + public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { + if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) { + return INDEX_NOT_FOUND; + } + final int csLen = cs.length(); + final int csLast = csLen - 1; + final int searchLen = searchChars.length; + final int searchLast = searchLen - 1; + outer: + for (int i = 0; i < csLen; i++) { + final char ch = cs.charAt(i); + for (int j = 0; j < searchLen; j++) { + if (searchChars[j] == ch) { + if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) { + if (searchChars[j + 1] == cs.charAt(i + 1)) { + continue outer; + } + } else { + continue outer; + } + } + } + return i; + } + return INDEX_NOT_FOUND; + } + + /** + *

              Search a CharSequence to find the first index of any + * character not in the given set of characters.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A {@code null} or empty search string will return {@code -1}.

              + * + *
              +     * StringUtils.indexOfAnyBut(null, *)            = -1
              +     * StringUtils.indexOfAnyBut("", *)              = -1
              +     * StringUtils.indexOfAnyBut(*, null)            = -1
              +     * StringUtils.indexOfAnyBut(*, "")              = -1
              +     * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
              +     * StringUtils.indexOfAnyBut("zzabyycdxx", "")   = -1
              +     * StringUtils.indexOfAnyBut("aba","ab")         = -1
              +     * 
              + * + * @param seq the CharSequence to check, may be null + * @param searchChars the chars to search for, may be null + * @return the index of any of the chars, -1 if no match or null input + * @since 2.0 + * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence) + */ + public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { + if (isEmpty(seq) || isEmpty(searchChars)) { + return INDEX_NOT_FOUND; + } + final int strLen = seq.length(); + for (int i = 0; i < strLen; i++) { + final char ch = seq.charAt(i); + final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0; + if (i + 1 < strLen && Character.isHighSurrogate(ch)) { + final char ch2 = seq.charAt(i + 1); + if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) { + return i; + } + } else { + if (!chFound) { + return i; + } + } + } + return INDEX_NOT_FOUND; + } + + // ContainsOnly + //----------------------------------------------------------------------- + /** + *

              Checks if the CharSequence contains only certain characters.

              + * + *

              A {@code null} CharSequence will return {@code false}. + * A {@code null} valid character array will return {@code false}. + * An empty CharSequence (length()=0) always returns {@code true}.

              + * + *
              +     * StringUtils.containsOnly(null, *)       = false
              +     * StringUtils.containsOnly(*, null)       = false
              +     * StringUtils.containsOnly("", *)         = true
              +     * StringUtils.containsOnly("ab", '')      = false
              +     * StringUtils.containsOnly("abab", 'abc') = true
              +     * StringUtils.containsOnly("ab1", 'abc')  = false
              +     * StringUtils.containsOnly("abz", 'abc')  = false
              +     * 
              + * + * @param cs the String to check, may be null + * @param valid an array of valid chars, may be null + * @return true if it only contains valid chars and is non-null + * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...) + */ + public static boolean containsOnly(final CharSequence cs, final char... valid) { + // All these pre-checks are to maintain API with an older version + if (valid == null || cs == null) { + return false; + } + if (cs.length() == 0) { + return true; + } + if (valid.length == 0) { + return false; + } + return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND; + } + + /** + *

              Checks if the CharSequence contains only certain characters.

              + * + *

              A {@code null} CharSequence will return {@code false}. + * A {@code null} valid character String will return {@code false}. + * An empty String (length()=0) always returns {@code true}.

              + * + *
              +     * StringUtils.containsOnly(null, *)       = false
              +     * StringUtils.containsOnly(*, null)       = false
              +     * StringUtils.containsOnly("", *)         = true
              +     * StringUtils.containsOnly("ab", "")      = false
              +     * StringUtils.containsOnly("abab", "abc") = true
              +     * StringUtils.containsOnly("ab1", "abc")  = false
              +     * StringUtils.containsOnly("abz", "abc")  = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @param validChars a String of valid chars, may be null + * @return true if it only contains valid chars and is non-null + * @since 2.0 + * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String) + */ + public static boolean containsOnly(final CharSequence cs, final String validChars) { + if (cs == null || validChars == null) { + return false; + } + return containsOnly(cs, validChars.toCharArray()); + } + + // ContainsNone + //----------------------------------------------------------------------- + /** + *

              Checks that the CharSequence does not contain certain characters.

              + * + *

              A {@code null} CharSequence will return {@code true}. + * A {@code null} invalid character array will return {@code true}. + * An empty CharSequence (length()=0) always returns true.

              + * + *
              +     * StringUtils.containsNone(null, *)       = true
              +     * StringUtils.containsNone(*, null)       = true
              +     * StringUtils.containsNone("", *)         = true
              +     * StringUtils.containsNone("ab", '')      = true
              +     * StringUtils.containsNone("abab", 'xyz') = true
              +     * StringUtils.containsNone("ab1", 'xyz')  = true
              +     * StringUtils.containsNone("abz", 'xyz')  = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @param searchChars an array of invalid chars, may be null + * @return true if it contains none of the invalid chars, or is null + * @since 2.0 + * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...) + */ + public static boolean containsNone(final CharSequence cs, final char... searchChars) { + if (cs == null || searchChars == null) { + return true; + } + final int csLen = cs.length(); + final int csLast = csLen - 1; + final int searchLen = searchChars.length; + final int searchLast = searchLen - 1; + for (int i = 0; i < csLen; i++) { + final char ch = cs.charAt(i); + for (int j = 0; j < searchLen; j++) { + if (searchChars[j] == ch) { + if (Character.isHighSurrogate(ch)) { + if (j == searchLast) { + // missing low surrogate, fine, like String.indexOf(String) + return false; + } + if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) { + return false; + } + } else { + // ch is in the Basic Multilingual Plane + return false; + } + } + } + } + return true; + } + + /** + *

              Checks that the CharSequence does not contain certain characters.

              + * + *

              A {@code null} CharSequence will return {@code true}. + * A {@code null} invalid character array will return {@code true}. + * An empty String ("") always returns true.

              + * + *
              +     * StringUtils.containsNone(null, *)       = true
              +     * StringUtils.containsNone(*, null)       = true
              +     * StringUtils.containsNone("", *)         = true
              +     * StringUtils.containsNone("ab", "")      = true
              +     * StringUtils.containsNone("abab", "xyz") = true
              +     * StringUtils.containsNone("ab1", "xyz")  = true
              +     * StringUtils.containsNone("abz", "xyz")  = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @param invalidChars a String of invalid chars, may be null + * @return true if it contains none of the invalid chars, or is null + * @since 2.0 + * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String) + */ + public static boolean containsNone(final CharSequence cs, final String invalidChars) { + if (cs == null || invalidChars == null) { + return true; + } + return containsNone(cs, invalidChars.toCharArray()); + } + + // IndexOfAny strings + //----------------------------------------------------------------------- + /** + *

              Find the first index of any of a set of potential substrings.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A {@code null} or zero length search array will return {@code -1}. + * A {@code null} search array entry will be ignored, but a search + * array containing "" will return {@code 0} if {@code str} is not + * null. This method uses {@link String#indexOf(String)} if possible.

              + * + *
              +     * StringUtils.indexOfAny(null, *)                     = -1
              +     * StringUtils.indexOfAny(*, null)                     = -1
              +     * StringUtils.indexOfAny(*, [])                       = -1
              +     * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"])   = 2
              +     * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"])   = 2
              +     * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"])   = -1
              +     * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
              +     * StringUtils.indexOfAny("zzabyycdxx", [""])          = 0
              +     * StringUtils.indexOfAny("", [""])                    = 0
              +     * StringUtils.indexOfAny("", ["a"])                   = -1
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStrs the CharSequences to search for, may be null + * @return the first index of any of the searchStrs in str, -1 if no match + * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...) + */ + public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { + if (str == null || searchStrs == null) { + return INDEX_NOT_FOUND; + } + + // String's can't have a MAX_VALUEth index. + int ret = Integer.MAX_VALUE; + + int tmp = 0; + for (final CharSequence search : searchStrs) { + if (search == null) { + continue; + } + tmp = CharSequenceUtils.indexOf(str, search, 0); + if (tmp == INDEX_NOT_FOUND) { + continue; + } + + if (tmp < ret) { + ret = tmp; + } + } + + return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret; + } + + /** + *

              Find the latest index of any of a set of potential substrings.

              + * + *

              A {@code null} CharSequence will return {@code -1}. + * A {@code null} search array will return {@code -1}. + * A {@code null} or zero length search array entry will be ignored, + * but a search array containing "" will return the length of {@code str} + * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible

              + * + *
              +     * StringUtils.lastIndexOfAny(null, *)                   = -1
              +     * StringUtils.lastIndexOfAny(*, null)                   = -1
              +     * StringUtils.lastIndexOfAny(*, [])                     = -1
              +     * StringUtils.lastIndexOfAny(*, [null])                 = -1
              +     * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
              +     * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
              +     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
              +     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
              +     * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""])   = 10
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param searchStrs the CharSequences to search for, may be null + * @return the last index of any of the CharSequences, -1 if no match + * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence) + */ + public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { + if (str == null || searchStrs == null) { + return INDEX_NOT_FOUND; + } + int ret = INDEX_NOT_FOUND; + int tmp = 0; + for (final CharSequence search : searchStrs) { + if (search == null) { + continue; + } + tmp = CharSequenceUtils.lastIndexOf(str, search, str.length()); + if (tmp > ret) { + ret = tmp; + } + } + return ret; + } + + // Substring + //----------------------------------------------------------------------- + /** + *

              Gets a substring from the specified String avoiding exceptions.

              + * + *

              A negative start position can be used to start {@code n} + * characters from the end of the String.

              + * + *

              A {@code null} String will return {@code null}. + * An empty ("") String will return "".

              + * + *
              +     * StringUtils.substring(null, *)   = null
              +     * StringUtils.substring("", *)     = ""
              +     * StringUtils.substring("abc", 0)  = "abc"
              +     * StringUtils.substring("abc", 2)  = "c"
              +     * StringUtils.substring("abc", 4)  = ""
              +     * StringUtils.substring("abc", -2) = "bc"
              +     * StringUtils.substring("abc", -4) = "abc"
              +     * 
              + * + * @param str the String to get the substring from, may be null + * @param start the position to start from, negative means + * count back from the end of the String by this many characters + * @return substring from start position, {@code null} if null String input + */ + public static String substring(final String str, int start) { + if (str == null) { + return null; + } + + // handle negatives, which means last n characters + if (start < 0) { + start = str.length() + start; // remember start is negative + } + + if (start < 0) { + start = 0; + } + if (start > str.length()) { + return EMPTY; + } + + return str.substring(start); + } + + /** + *

              Gets a substring from the specified String avoiding exceptions.

              + * + *

              A negative start position can be used to start/end {@code n} + * characters from the end of the String.

              + * + *

              The returned substring starts with the character in the {@code start} + * position and ends before the {@code end} position. All position counting is + * zero-based -- i.e., to start at the beginning of the string use + * {@code start = 0}. Negative start and end positions can be used to + * specify offsets relative to the end of the String.

              + * + *

              If {@code start} is not strictly to the left of {@code end}, "" + * is returned.

              + * + *
              +     * StringUtils.substring(null, *, *)    = null
              +     * StringUtils.substring("", * ,  *)    = "";
              +     * StringUtils.substring("abc", 0, 2)   = "ab"
              +     * StringUtils.substring("abc", 2, 0)   = ""
              +     * StringUtils.substring("abc", 2, 4)   = "c"
              +     * StringUtils.substring("abc", 4, 6)   = ""
              +     * StringUtils.substring("abc", 2, 2)   = ""
              +     * StringUtils.substring("abc", -2, -1) = "b"
              +     * StringUtils.substring("abc", -4, 2)  = "ab"
              +     * 
              + * + * @param str the String to get the substring from, may be null + * @param start the position to start from, negative means + * count back from the end of the String by this many characters + * @param end the position to end at (exclusive), negative means + * count back from the end of the String by this many characters + * @return substring from start position to end position, + * {@code null} if null String input + */ + public static String substring(final String str, int start, int end) { + if (str == null) { + return null; + } + + // handle negatives + if (end < 0) { + end = str.length() + end; // remember end is negative + } + if (start < 0) { + start = str.length() + start; // remember start is negative + } + + // check length next + if (end > str.length()) { + end = str.length(); + } + + // if start is greater than end, return "" + if (start > end) { + return EMPTY; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } + + // Left/Right/Mid + //----------------------------------------------------------------------- + /** + *

              Gets the leftmost {@code len} characters of a String.

              + * + *

              If {@code len} characters are not available, or the + * String is {@code null}, the String will be returned without + * an exception. An empty String is returned if len is negative.

              + * + *
              +     * StringUtils.left(null, *)    = null
              +     * StringUtils.left(*, -ve)     = ""
              +     * StringUtils.left("", *)      = ""
              +     * StringUtils.left("abc", 0)   = ""
              +     * StringUtils.left("abc", 2)   = "ab"
              +     * StringUtils.left("abc", 4)   = "abc"
              +     * 
              + * + * @param str the String to get the leftmost characters from, may be null + * @param len the length of the required String + * @return the leftmost characters, {@code null} if null String input + */ + public static String left(final String str, final int len) { + if (str == null) { + return null; + } + if (len < 0) { + return EMPTY; + } + if (str.length() <= len) { + return str; + } + return str.substring(0, len); + } + + /** + *

              Gets the rightmost {@code len} characters of a String.

              + * + *

              If {@code len} characters are not available, or the String + * is {@code null}, the String will be returned without an + * an exception. An empty String is returned if len is negative.

              + * + *
              +     * StringUtils.right(null, *)    = null
              +     * StringUtils.right(*, -ve)     = ""
              +     * StringUtils.right("", *)      = ""
              +     * StringUtils.right("abc", 0)   = ""
              +     * StringUtils.right("abc", 2)   = "bc"
              +     * StringUtils.right("abc", 4)   = "abc"
              +     * 
              + * + * @param str the String to get the rightmost characters from, may be null + * @param len the length of the required String + * @return the rightmost characters, {@code null} if null String input + */ + public static String right(final String str, final int len) { + if (str == null) { + return null; + } + if (len < 0) { + return EMPTY; + } + if (str.length() <= len) { + return str; + } + return str.substring(str.length() - len); + } + + /** + *

              Gets {@code len} characters from the middle of a String.

              + * + *

              If {@code len} characters are not available, the remainder + * of the String will be returned without an exception. If the + * String is {@code null}, {@code null} will be returned. + * An empty String is returned if len is negative or exceeds the + * length of {@code str}.

              + * + *
              +     * StringUtils.mid(null, *, *)    = null
              +     * StringUtils.mid(*, *, -ve)     = ""
              +     * StringUtils.mid("", 0, *)      = ""
              +     * StringUtils.mid("abc", 0, 2)   = "ab"
              +     * StringUtils.mid("abc", 0, 4)   = "abc"
              +     * StringUtils.mid("abc", 2, 4)   = "c"
              +     * StringUtils.mid("abc", 4, 2)   = ""
              +     * StringUtils.mid("abc", -2, 2)  = "ab"
              +     * 
              + * + * @param str the String to get the characters from, may be null + * @param pos the position to start from, negative treated as zero + * @param len the length of the required String + * @return the middle characters, {@code null} if null String input + */ + public static String mid(final String str, int pos, final int len) { + if (str == null) { + return null; + } + if (len < 0 || pos > str.length()) { + return EMPTY; + } + if (pos < 0) { + pos = 0; + } + if (str.length() <= pos + len) { + return str.substring(pos); + } + return str.substring(pos, pos + len); + } + + // SubStringAfter/SubStringBefore + //----------------------------------------------------------------------- + /** + *

              Gets the substring before the first occurrence of a separator. + * The separator is not returned.

              + * + *

              A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * A {@code null} separator will return the input string.

              + * + *

              If nothing is found, the string input is returned.

              + * + *
              +     * StringUtils.substringBefore(null, *)      = null
              +     * StringUtils.substringBefore("", *)        = ""
              +     * StringUtils.substringBefore("abc", "a")   = ""
              +     * StringUtils.substringBefore("abcba", "b") = "a"
              +     * StringUtils.substringBefore("abc", "c")   = "ab"
              +     * StringUtils.substringBefore("abc", "d")   = "abc"
              +     * StringUtils.substringBefore("abc", "")    = ""
              +     * StringUtils.substringBefore("abc", null)  = "abc"
              +     * 
              + * + * @param str the String to get a substring from, may be null + * @param separator the String to search for, may be null + * @return the substring before the first occurrence of the separator, + * {@code null} if null String input + * @since 2.0 + */ + public static String substringBefore(final String str, final String separator) { + if (isEmpty(str) || separator == null) { + return str; + } + if (separator.isEmpty()) { + return EMPTY; + } + final int pos = str.indexOf(separator); + if (pos == INDEX_NOT_FOUND) { + return str; + } + return str.substring(0, pos); + } + + /** + *

              Gets the substring after the first occurrence of a separator. + * The separator is not returned.

              + * + *

              A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * A {@code null} separator will return the empty string if the + * input string is not {@code null}.

              + * + *

              If nothing is found, the empty string is returned.

              + * + *
              +     * StringUtils.substringAfter(null, *)      = null
              +     * StringUtils.substringAfter("", *)        = ""
              +     * StringUtils.substringAfter(*, null)      = ""
              +     * StringUtils.substringAfter("abc", "a")   = "bc"
              +     * StringUtils.substringAfter("abcba", "b") = "cba"
              +     * StringUtils.substringAfter("abc", "c")   = ""
              +     * StringUtils.substringAfter("abc", "d")   = ""
              +     * StringUtils.substringAfter("abc", "")    = "abc"
              +     * 
              + * + * @param str the String to get a substring from, may be null + * @param separator the String to search for, may be null + * @return the substring after the first occurrence of the separator, + * {@code null} if null String input + * @since 2.0 + */ + public static String substringAfter(final String str, final String separator) { + if (isEmpty(str)) { + return str; + } + if (separator == null) { + return EMPTY; + } + final int pos = str.indexOf(separator); + if (pos == INDEX_NOT_FOUND) { + return EMPTY; + } + return str.substring(pos + separator.length()); + } + + /** + *

              Gets the substring before the last occurrence of a separator. + * The separator is not returned.

              + * + *

              A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * An empty or {@code null} separator will return the input string.

              + * + *

              If nothing is found, the string input is returned.

              + * + *
              +     * StringUtils.substringBeforeLast(null, *)      = null
              +     * StringUtils.substringBeforeLast("", *)        = ""
              +     * StringUtils.substringBeforeLast("abcba", "b") = "abc"
              +     * StringUtils.substringBeforeLast("abc", "c")   = "ab"
              +     * StringUtils.substringBeforeLast("a", "a")     = ""
              +     * StringUtils.substringBeforeLast("a", "z")     = "a"
              +     * StringUtils.substringBeforeLast("a", null)    = "a"
              +     * StringUtils.substringBeforeLast("a", "")      = "a"
              +     * 
              + * + * @param str the String to get a substring from, may be null + * @param separator the String to search for, may be null + * @return the substring before the last occurrence of the separator, + * {@code null} if null String input + * @since 2.0 + */ + public static String substringBeforeLast(final String str, final String separator) { + if (isEmpty(str) || isEmpty(separator)) { + return str; + } + final int pos = str.lastIndexOf(separator); + if (pos == INDEX_NOT_FOUND) { + return str; + } + return str.substring(0, pos); + } + + /** + *

              Gets the substring after the last occurrence of a separator. + * The separator is not returned.

              + * + *

              A {@code null} string input will return {@code null}. + * An empty ("") string input will return the empty string. + * An empty or {@code null} separator will return the empty string if + * the input string is not {@code null}.

              + * + *

              If nothing is found, the empty string is returned.

              + * + *
              +     * StringUtils.substringAfterLast(null, *)      = null
              +     * StringUtils.substringAfterLast("", *)        = ""
              +     * StringUtils.substringAfterLast(*, "")        = ""
              +     * StringUtils.substringAfterLast(*, null)      = ""
              +     * StringUtils.substringAfterLast("abc", "a")   = "bc"
              +     * StringUtils.substringAfterLast("abcba", "b") = "a"
              +     * StringUtils.substringAfterLast("abc", "c")   = ""
              +     * StringUtils.substringAfterLast("a", "a")     = ""
              +     * StringUtils.substringAfterLast("a", "z")     = ""
              +     * 
              + * + * @param str the String to get a substring from, may be null + * @param separator the String to search for, may be null + * @return the substring after the last occurrence of the separator, + * {@code null} if null String input + * @since 2.0 + */ + public static String substringAfterLast(final String str, final String separator) { + if (isEmpty(str)) { + return str; + } + if (isEmpty(separator)) { + return EMPTY; + } + final int pos = str.lastIndexOf(separator); + if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { + return EMPTY; + } + return str.substring(pos + separator.length()); + } + + // Substring between + //----------------------------------------------------------------------- + /** + *

              Gets the String that is nested in between two instances of the + * same String.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} tag returns {@code null}.

              + * + *
              +     * StringUtils.substringBetween(null, *)            = null
              +     * StringUtils.substringBetween("", "")             = ""
              +     * StringUtils.substringBetween("", "tag")          = null
              +     * StringUtils.substringBetween("tagabctag", null)  = null
              +     * StringUtils.substringBetween("tagabctag", "")    = ""
              +     * StringUtils.substringBetween("tagabctag", "tag") = "abc"
              +     * 
              + * + * @param str the String containing the substring, may be null + * @param tag the String before and after the substring, may be null + * @return the substring, {@code null} if no match + * @since 2.0 + */ + public static String substringBetween(final String str, final String tag) { + return substringBetween(str, tag, tag); + } + + /** + *

              Gets the String that is nested in between two Strings. + * Only the first match is returned.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} open/close returns {@code null} (no match). + * An empty ("") open and close returns an empty string.

              + * + *
              +     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
              +     * StringUtils.substringBetween(null, *, *)          = null
              +     * StringUtils.substringBetween(*, null, *)          = null
              +     * StringUtils.substringBetween(*, *, null)          = null
              +     * StringUtils.substringBetween("", "", "")          = ""
              +     * StringUtils.substringBetween("", "", "]")         = null
              +     * StringUtils.substringBetween("", "[", "]")        = null
              +     * StringUtils.substringBetween("yabcz", "", "")     = ""
              +     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
              +     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
              +     * 
              + * + * @param str the String containing the substring, may be null + * @param open the String before the substring, may be null + * @param close the String after the substring, may be null + * @return the substring, {@code null} if no match + * @since 2.0 + */ + public static String substringBetween(final String str, final String open, final String close) { + if (str == null || open == null || close == null) { + return null; + } + final int start = str.indexOf(open); + if (start != INDEX_NOT_FOUND) { + final int end = str.indexOf(close, start + open.length()); + if (end != INDEX_NOT_FOUND) { + return str.substring(start + open.length(), end); + } + } + return null; + } + + /** + *

              Searches a String for substrings delimited by a start and end tag, + * returning all matching substrings in an array.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} open/close returns {@code null} (no match). + * An empty ("") open/close returns {@code null} (no match).

              + * + *
              +     * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
              +     * StringUtils.substringsBetween(null, *, *)            = null
              +     * StringUtils.substringsBetween(*, null, *)            = null
              +     * StringUtils.substringsBetween(*, *, null)            = null
              +     * StringUtils.substringsBetween("", "[", "]")          = []
              +     * 
              + * + * @param str the String containing the substrings, null returns null, empty returns empty + * @param open the String identifying the start of the substring, empty returns null + * @param close the String identifying the end of the substring, empty returns null + * @return a String Array of substrings, or {@code null} if no match + * @since 2.3 + */ + public static String[] substringsBetween(final String str, final String open, final String close) { + if (str == null || isEmpty(open) || isEmpty(close)) { + return null; + } + final int strLen = str.length(); + if (strLen == 0) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + final int closeLen = close.length(); + final int openLen = open.length(); + final List list = new ArrayList<>(); + int pos = 0; + while (pos < strLen - closeLen) { + int start = str.indexOf(open, pos); + if (start < 0) { + break; + } + start += openLen; + final int end = str.indexOf(close, start); + if (end < 0) { + break; + } + list.add(str.substring(start, end)); + pos = end + closeLen; + } + if (list.isEmpty()) { + return null; + } + return list.toArray(new String [list.size()]); + } + + // Nested extraction + //----------------------------------------------------------------------- + + // Splitting + //----------------------------------------------------------------------- + /** + *

              Splits the provided text into an array, using whitespace as the + * separator. + * Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as one separator. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.split(null)       = null
              +     * StringUtils.split("")         = []
              +     * StringUtils.split("abc def")  = ["abc", "def"]
              +     * StringUtils.split("abc  def") = ["abc", "def"]
              +     * StringUtils.split(" abc ")    = ["abc"]
              +     * 
              + * + * @param str the String to parse, may be null + * @return an array of parsed Strings, {@code null} if null String input + */ + public static String[] split(final String str) { + return split(str, null, -1); + } + + /** + *

              Splits the provided text into an array, separator specified. + * This is an alternative to using StringTokenizer.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as one separator. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.split(null, *)         = null
              +     * StringUtils.split("", *)           = []
              +     * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
              +     * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
              +     * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
              +     * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
              +     * 
              + * + * @param str the String to parse, may be null + * @param separatorChar the character used as the delimiter + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.0 + */ + public static String[] split(final String str, final char separatorChar) { + return splitWorker(str, separatorChar, false); + } + + /** + *

              Splits the provided text into an array, separators specified. + * This is an alternative to using StringTokenizer.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as one separator. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.

              + * + *
              +     * StringUtils.split(null, *)         = null
              +     * StringUtils.split("", *)           = []
              +     * StringUtils.split("abc def", null) = ["abc", "def"]
              +     * StringUtils.split("abc def", " ")  = ["abc", "def"]
              +     * StringUtils.split("abc  def", " ") = ["abc", "def"]
              +     * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
              +     * 
              + * + * @param str the String to parse, may be null + * @param separatorChars the characters used as the delimiters, + * {@code null} splits on whitespace + * @return an array of parsed Strings, {@code null} if null String input + */ + public static String[] split(final String str, final String separatorChars) { + return splitWorker(str, separatorChars, -1, false); + } + + /** + *

              Splits the provided text into an array with a maximum length, + * separators specified.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as one separator.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.

              + * + *

              If more than {@code max} delimited substrings are found, the last + * returned string includes all characters after the first {@code max - 1} + * returned strings (including separator characters).

              + * + *
              +     * StringUtils.split(null, *, *)            = null
              +     * StringUtils.split("", *, *)              = []
              +     * StringUtils.split("ab cd ef", null, 0)   = ["ab", "cd", "ef"]
              +     * StringUtils.split("ab   cd ef", null, 0) = ["ab", "cd", "ef"]
              +     * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
              +     * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
              +     * 
              + * + * @param str the String to parse, may be null + * @param separatorChars the characters used as the delimiters, + * {@code null} splits on whitespace + * @param max the maximum number of elements to include in the + * array. A zero or negative value implies no limit + * @return an array of parsed Strings, {@code null} if null String input + */ + public static String[] split(final String str, final String separatorChars, final int max) { + return splitWorker(str, separatorChars, max, false); + } + + /** + *

              Splits the provided text into an array, separator string specified.

              + * + *

              The separator(s) will not be included in the returned String array. + * Adjacent separators are treated as one separator.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.

              + * + *
              +     * StringUtils.splitByWholeSeparator(null, *)               = null
              +     * StringUtils.splitByWholeSeparator("", *)                 = []
              +     * StringUtils.splitByWholeSeparator("ab de fg", null)      = ["ab", "de", "fg"]
              +     * StringUtils.splitByWholeSeparator("ab   de fg", null)    = ["ab", "de", "fg"]
              +     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
              +     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
              +     * 
              + * + * @param str the String to parse, may be null + * @param separator String containing the String to be used as a delimiter, + * {@code null} splits on whitespace + * @return an array of parsed Strings, {@code null} if null String was input + */ + public static String[] splitByWholeSeparator(final String str, final String separator) { + return splitByWholeSeparatorWorker( str, separator, -1, false ) ; + } + + /** + *

              Splits the provided text into an array, separator string specified. + * Returns a maximum of {@code max} substrings.

              + * + *

              The separator(s) will not be included in the returned String array. + * Adjacent separators are treated as one separator.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.

              + * + *
              +     * StringUtils.splitByWholeSeparator(null, *, *)               = null
              +     * StringUtils.splitByWholeSeparator("", *, *)                 = []
              +     * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
              +     * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
              +     * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
              +     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
              +     * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
              +     * 
              + * + * @param str the String to parse, may be null + * @param separator String containing the String to be used as a delimiter, + * {@code null} splits on whitespace + * @param max the maximum number of elements to include in the returned + * array. A zero or negative value implies no limit. + * @return an array of parsed Strings, {@code null} if null String was input + */ + public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { + return splitByWholeSeparatorWorker(str, separator, max, false); + } + + /** + *

              Splits the provided text into an array, separator string specified.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.

              + * + *
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *)               = null
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *)                 = []
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null)      = ["ab", "de", "fg"]
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null)    = ["ab", "", "", "de", "fg"]
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":")       = ["ab", "cd", "ef"]
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
              +     * 
              + * + * @param str the String to parse, may be null + * @param separator String containing the String to be used as a delimiter, + * {@code null} splits on whitespace + * @return an array of parsed Strings, {@code null} if null String was input + * @since 2.4 + */ + public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { + return splitByWholeSeparatorWorker(str, separator, -1, true); + } + + /** + *

              Splits the provided text into an array, separator string specified. + * Returns a maximum of {@code max} substrings.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separator splits on whitespace.

              + * + *
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *)               = null
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *)                 = []
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0)      = ["ab", "de", "fg"]
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab   de fg", null, 0)    = ["ab", "", "", "de", "fg"]
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2)       = ["ab", "cd:ef"]
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
              +     * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
              +     * 
              + * + * @param str the String to parse, may be null + * @param separator String containing the String to be used as a delimiter, + * {@code null} splits on whitespace + * @param max the maximum number of elements to include in the returned + * array. A zero or negative value implies no limit. + * @return an array of parsed Strings, {@code null} if null String was input + * @since 2.4 + */ + public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { + return splitByWholeSeparatorWorker(str, separator, max, true); + } + + /** + * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods. + * + * @param str the String to parse, may be {@code null} + * @param separator String containing the String to be used as a delimiter, + * {@code null} splits on whitespace + * @param max the maximum number of elements to include in the returned + * array. A zero or negative value implies no limit. + * @param preserveAllTokens if {@code true}, adjacent separators are + * treated as empty token separators; if {@code false}, adjacent + * separators are treated as one separator. + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.4 + */ + private static String[] splitByWholeSeparatorWorker( + final String str, final String separator, final int max, final boolean preserveAllTokens) { + if (str == null) { + return null; + } + + final int len = str.length(); + + if (len == 0) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + + if (separator == null || EMPTY.equals(separator)) { + // Split on whitespace. + return splitWorker(str, null, max, preserveAllTokens); + } + + final int separatorLength = separator.length(); + + final ArrayList substrings = new ArrayList<>(); + int numberOfSubstrings = 0; + int beg = 0; + int end = 0; + while (end < len) { + end = str.indexOf(separator, beg); + + if (end > -1) { + if (end > beg) { + numberOfSubstrings += 1; + + if (numberOfSubstrings == max) { + end = len; + substrings.add(str.substring(beg)); + } else { + // The following is OK, because String.substring( beg, end ) excludes + // the character at the position 'end'. + substrings.add(str.substring(beg, end)); + + // Set the starting point for the next search. + // The following is equivalent to beg = end + (separatorLength - 1) + 1, + // which is the right calculation: + beg = end + separatorLength; + } + } else { + // We found a consecutive occurrence of the separator, so skip it. + if (preserveAllTokens) { + numberOfSubstrings += 1; + if (numberOfSubstrings == max) { + end = len; + substrings.add(str.substring(beg)); + } else { + substrings.add(EMPTY); + } + } + beg = end + separatorLength; + } + } else { + // String.substring( beg ) goes from 'beg' to the end of the String. + substrings.add(str.substring(beg)); + end = len; + } + } + + return substrings.toArray(new String[substrings.size()]); + } + + // ----------------------------------------------------------------------- + /** + *

              Splits the provided text into an array, using whitespace as the + * separator, preserving all tokens, including empty tokens created by + * adjacent separators. This is an alternative to using StringTokenizer. + * Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.splitPreserveAllTokens(null)       = null
              +     * StringUtils.splitPreserveAllTokens("")         = []
              +     * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
              +     * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
              +     * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
              +     * 
              + * + * @param str the String to parse, may be {@code null} + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.1 + */ + public static String[] splitPreserveAllTokens(final String str) { + return splitWorker(str, null, -1, true); + } + + /** + *

              Splits the provided text into an array, separator specified, + * preserving all tokens, including empty tokens created by adjacent + * separators. This is an alternative to using StringTokenizer.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.splitPreserveAllTokens(null, *)         = null
              +     * StringUtils.splitPreserveAllTokens("", *)           = []
              +     * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
              +     * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "", "b", "c"]
              +     * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
              +     * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
              +     * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
              +     * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
              +     * StringUtils.splitPreserveAllTokens("a b c  ", ' ')   = ["a", "b", "c", "", ""]
              +     * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
              +     * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
              +     * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
              +     * 
              + * + * @param str the String to parse, may be {@code null} + * @param separatorChar the character used as the delimiter, + * {@code null} splits on whitespace + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.1 + */ + public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { + return splitWorker(str, separatorChar, true); + } + + /** + * Performs the logic for the {@code split} and + * {@code splitPreserveAllTokens} methods that do not return a + * maximum array length. + * + * @param str the String to parse, may be {@code null} + * @param separatorChar the separate character + * @param preserveAllTokens if {@code true}, adjacent separators are + * treated as empty token separators; if {@code false}, adjacent + * separators are treated as one separator. + * @return an array of parsed Strings, {@code null} if null String input + */ + private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) { + // Performance tuned for 2.0 (JDK1.4) + + if (str == null) { + return null; + } + final int len = str.length(); + if (len == 0) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + final List list = new ArrayList<>(); + int i = 0, start = 0; + boolean match = false; + boolean lastMatch = false; + while (i < len) { + if (str.charAt(i) == separatorChar) { + if (match || preserveAllTokens) { + list.add(str.substring(start, i)); + match = false; + lastMatch = true; + } + start = ++i; + continue; + } + lastMatch = false; + match = true; + i++; + } + if (match || preserveAllTokens && lastMatch) { + list.add(str.substring(start, i)); + } + return list.toArray(new String[list.size()]); + } + + /** + *

              Splits the provided text into an array, separators specified, + * preserving all tokens, including empty tokens created by adjacent + * separators. This is an alternative to using StringTokenizer.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * For more control over the split use the StrTokenizer class.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.

              + * + *
              +     * StringUtils.splitPreserveAllTokens(null, *)           = null
              +     * StringUtils.splitPreserveAllTokens("", *)             = []
              +     * StringUtils.splitPreserveAllTokens("abc def", null)   = ["abc", "def"]
              +     * StringUtils.splitPreserveAllTokens("abc def", " ")    = ["abc", "def"]
              +     * StringUtils.splitPreserveAllTokens("abc  def", " ")   = ["abc", "", def"]
              +     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":")   = ["ab", "cd", "ef"]
              +     * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":")  = ["ab", "cd", "ef", ""]
              +     * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
              +     * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":")  = ["ab", "", cd", "ef"]
              +     * StringUtils.splitPreserveAllTokens(":cd:ef", ":")     = ["", cd", "ef"]
              +     * StringUtils.splitPreserveAllTokens("::cd:ef", ":")    = ["", "", cd", "ef"]
              +     * StringUtils.splitPreserveAllTokens(":cd:ef:", ":")    = ["", cd", "ef", ""]
              +     * 
              + * + * @param str the String to parse, may be {@code null} + * @param separatorChars the characters used as the delimiters, + * {@code null} splits on whitespace + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.1 + */ + public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { + return splitWorker(str, separatorChars, -1, true); + } + + /** + *

              Splits the provided text into an array with a maximum length, + * separators specified, preserving all tokens, including empty tokens + * created by adjacent separators.

              + * + *

              The separator is not included in the returned String array. + * Adjacent separators are treated as separators for empty tokens. + * Adjacent separators are treated as one separator.

              + * + *

              A {@code null} input String returns {@code null}. + * A {@code null} separatorChars splits on whitespace.

              + * + *

              If more than {@code max} delimited substrings are found, the last + * returned string includes all characters after the first {@code max - 1} + * returned strings (including separator characters).

              + * + *
              +     * StringUtils.splitPreserveAllTokens(null, *, *)            = null
              +     * StringUtils.splitPreserveAllTokens("", *, *)              = []
              +     * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "cd", "ef"]
              +     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "cd", "ef"]
              +     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
              +     * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
              +     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
              +     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
              +     * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
              +     * 
              + * + * @param str the String to parse, may be {@code null} + * @param separatorChars the characters used as the delimiters, + * {@code null} splits on whitespace + * @param max the maximum number of elements to include in the + * array. A zero or negative value implies no limit + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.1 + */ + public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { + return splitWorker(str, separatorChars, max, true); + } + + /** + * Performs the logic for the {@code split} and + * {@code splitPreserveAllTokens} methods that return a maximum array + * length. + * + * @param str the String to parse, may be {@code null} + * @param separatorChars the separate character + * @param max the maximum number of elements to include in the + * array. A zero or negative value implies no limit. + * @param preserveAllTokens if {@code true}, adjacent separators are + * treated as empty token separators; if {@code false}, adjacent + * separators are treated as one separator. + * @return an array of parsed Strings, {@code null} if null String input + */ + private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) { + // Performance tuned for 2.0 (JDK1.4) + // Direct code is quicker than StringTokenizer. + // Also, StringTokenizer uses isSpace() not isWhitespace() + + if (str == null) { + return null; + } + final int len = str.length(); + if (len == 0) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + final List list = new ArrayList<>(); + int sizePlus1 = 1; + int i = 0, start = 0; + boolean match = false; + boolean lastMatch = false; + if (separatorChars == null) { + // Null separator means use whitespace + while (i < len) { + if (Character.isWhitespace(str.charAt(i))) { + if (match || preserveAllTokens) { + lastMatch = true; + if (sizePlus1++ == max) { + i = len; + lastMatch = false; + } + list.add(str.substring(start, i)); + match = false; + } + start = ++i; + continue; + } + lastMatch = false; + match = true; + i++; + } + } else if (separatorChars.length() == 1) { + // Optimise 1 character case + final char sep = separatorChars.charAt(0); + while (i < len) { + if (str.charAt(i) == sep) { + if (match || preserveAllTokens) { + lastMatch = true; + if (sizePlus1++ == max) { + i = len; + lastMatch = false; + } + list.add(str.substring(start, i)); + match = false; + } + start = ++i; + continue; + } + lastMatch = false; + match = true; + i++; + } + } else { + // standard case + while (i < len) { + if (separatorChars.indexOf(str.charAt(i)) >= 0) { + if (match || preserveAllTokens) { + lastMatch = true; + if (sizePlus1++ == max) { + i = len; + lastMatch = false; + } + list.add(str.substring(start, i)); + match = false; + } + start = ++i; + continue; + } + lastMatch = false; + match = true; + i++; + } + } + if (match || preserveAllTokens && lastMatch) { + list.add(str.substring(start, i)); + } + return list.toArray(new String[list.size()]); + } + + /** + *

              Splits a String by Character type as returned by + * {@code java.lang.Character.getType(char)}. Groups of contiguous + * characters of the same type are returned as complete tokens. + *

              +     * StringUtils.splitByCharacterType(null)         = null
              +     * StringUtils.splitByCharacterType("")           = []
              +     * StringUtils.splitByCharacterType("ab de fg")   = ["ab", " ", "de", " ", "fg"]
              +     * StringUtils.splitByCharacterType("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
              +     * StringUtils.splitByCharacterType("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
              +     * StringUtils.splitByCharacterType("number5")    = ["number", "5"]
              +     * StringUtils.splitByCharacterType("fooBar")     = ["foo", "B", "ar"]
              +     * StringUtils.splitByCharacterType("foo200Bar")  = ["foo", "200", "B", "ar"]
              +     * StringUtils.splitByCharacterType("ASFRules")   = ["ASFR", "ules"]
              +     * 
              + * @param str the String to split, may be {@code null} + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.4 + */ + public static String[] splitByCharacterType(final String str) { + return splitByCharacterType(str, false); + } + + /** + *

              Splits a String by Character type as returned by + * {@code java.lang.Character.getType(char)}. Groups of contiguous + * characters of the same type are returned as complete tokens, with the + * following exception: the character of type + * {@code Character.UPPERCASE_LETTER}, if any, immediately + * preceding a token of type {@code Character.LOWERCASE_LETTER} + * will belong to the following token rather than to the preceding, if any, + * {@code Character.UPPERCASE_LETTER} token. + *

              +     * StringUtils.splitByCharacterTypeCamelCase(null)         = null
              +     * StringUtils.splitByCharacterTypeCamelCase("")           = []
              +     * StringUtils.splitByCharacterTypeCamelCase("ab de fg")   = ["ab", " ", "de", " ", "fg"]
              +     * StringUtils.splitByCharacterTypeCamelCase("ab   de fg") = ["ab", "   ", "de", " ", "fg"]
              +     * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef")   = ["ab", ":", "cd", ":", "ef"]
              +     * StringUtils.splitByCharacterTypeCamelCase("number5")    = ["number", "5"]
              +     * StringUtils.splitByCharacterTypeCamelCase("fooBar")     = ["foo", "Bar"]
              +     * StringUtils.splitByCharacterTypeCamelCase("foo200Bar")  = ["foo", "200", "Bar"]
              +     * StringUtils.splitByCharacterTypeCamelCase("ASFRules")   = ["ASF", "Rules"]
              +     * 
              + * @param str the String to split, may be {@code null} + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.4 + */ + public static String[] splitByCharacterTypeCamelCase(final String str) { + return splitByCharacterType(str, true); + } + + /** + *

              Splits a String by Character type as returned by + * {@code java.lang.Character.getType(char)}. Groups of contiguous + * characters of the same type are returned as complete tokens, with the + * following exception: if {@code camelCase} is {@code true}, + * the character of type {@code Character.UPPERCASE_LETTER}, if any, + * immediately preceding a token of type {@code Character.LOWERCASE_LETTER} + * will belong to the following token rather than to the preceding, if any, + * {@code Character.UPPERCASE_LETTER} token. + * @param str the String to split, may be {@code null} + * @param camelCase whether to use so-called "camel-case" for letter types + * @return an array of parsed Strings, {@code null} if null String input + * @since 2.4 + */ + private static String[] splitByCharacterType(final String str, final boolean camelCase) { + if (str == null) { + return null; + } + if (str.isEmpty()) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + final char[] c = str.toCharArray(); + final List list = new ArrayList<>(); + int tokenStart = 0; + int currentType = Character.getType(c[tokenStart]); + for (int pos = tokenStart + 1; pos < c.length; pos++) { + final int type = Character.getType(c[pos]); + if (type == currentType) { + continue; + } + if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) { + final int newTokenStart = pos - 1; + if (newTokenStart != tokenStart) { + list.add(new String(c, tokenStart, newTokenStart - tokenStart)); + tokenStart = newTokenStart; + } + } else { + list.add(new String(c, tokenStart, pos - tokenStart)); + tokenStart = pos; + } + currentType = type; + } + list.add(new String(c, tokenStart, c.length - tokenStart)); + return list.toArray(new String[list.size()]); + } + + // Joining + //----------------------------------------------------------------------- + /** + *

              Joins the elements of the provided array into a single String + * containing the provided list of elements.

              + * + *

              No separator is added to the joined String. + * Null objects or empty strings within the array are represented by + * empty strings.

              + * + *
              +     * StringUtils.join(null)            = null
              +     * StringUtils.join([])              = ""
              +     * StringUtils.join([null])          = ""
              +     * StringUtils.join(["a", "b", "c"]) = "abc"
              +     * StringUtils.join([null, "", "a"]) = "a"
              +     * 
              + * + * @param the specific type of values to join together + * @param elements the values to join together, may be null + * @return the joined String, {@code null} if null array input + * @since 2.0 + * @since 3.0 Changed signature to use varargs + */ + @SafeVarargs + public static String join(final T... elements) { + return join(elements, null); + } + + /** + *

              Joins the elements of the provided array into a single String + * containing the provided list of elements.

              + * + *

              No delimiter is added before or after the list. + * Null objects or empty strings within the array are represented by + * empty strings.

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
              +     * StringUtils.join(["a", "b", "c"], null) = "abc"
              +     * StringUtils.join([null, "", "a"], ';')  = ";;a"
              +     * 
              + * + * @param array the array of values to join together, may be null + * @param separator the separator character to use + * @return the joined String, {@code null} if null array input + * @since 2.0 + */ + public static String join(final Object[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final long[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final int[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final short[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final byte[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final char[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final float[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final double[] array, final char separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + + /** + *

              Joins the elements of the provided array into a single String + * containing the provided list of elements.

              + * + *

              No delimiter is added before or after the list. + * Null objects or empty strings within the array are represented by + * empty strings.

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
              +     * StringUtils.join(["a", "b", "c"], null) = "abc"
              +     * StringUtils.join([null, "", "a"], ';')  = ";;a"
              +     * 
              + * + * @param array the array of values to join together, may be null + * @param separator the separator character to use + * @param startIndex the first index to start joining from. It is + * an error to pass in an end index past the end of the array + * @param endIndex the index to stop joining from (exclusive). It is + * an error to pass in an end index past the end of the array + * @return the joined String, {@code null} if null array input + * @since 2.0 + */ + public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + if (array[i] != null) { + buf.append(array[i]); + } + } + return buf.toString(); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @param startIndex + * the first index to start joining from. It is an error to pass in an end index past the end of the + * array + * @param endIndex + * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of + * the array + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + buf.append(array[i]); + } + return buf.toString(); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @param startIndex + * the first index to start joining from. It is an error to pass in an end index past the end of the + * array + * @param endIndex + * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of + * the array + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + buf.append(array[i]); + } + return buf.toString(); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @param startIndex + * the first index to start joining from. It is an error to pass in an end index past the end of the + * array + * @param endIndex + * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of + * the array + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + buf.append(array[i]); + } + return buf.toString(); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @param startIndex + * the first index to start joining from. It is an error to pass in an end index past the end of the + * array + * @param endIndex + * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of + * the array + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + buf.append(array[i]); + } + return buf.toString(); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @param startIndex + * the first index to start joining from. It is an error to pass in an end index past the end of the + * array + * @param endIndex + * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of + * the array + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + buf.append(array[i]); + } + return buf.toString(); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @param startIndex + * the first index to start joining from. It is an error to pass in an end index past the end of the + * array + * @param endIndex + * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of + * the array + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + buf.append(array[i]); + } + return buf.toString(); + } + + /** + *

              + * Joins the elements of the provided array into a single String containing the provided list of elements. + *

              + * + *

              + * No delimiter is added before or after the list. Null objects or empty strings within the array are represented + * by empty strings. + *

              + * + *
              +     * StringUtils.join(null, *)               = null
              +     * StringUtils.join([], *)                 = ""
              +     * StringUtils.join([null], *)             = ""
              +     * StringUtils.join([1, 2, 3], ';')  = "1;2;3"
              +     * StringUtils.join([1, 2, 3], null) = "123"
              +     * 
              + * + * @param array + * the array of values to join together, may be null + * @param separator + * the separator character to use + * @param startIndex + * the first index to start joining from. It is an error to pass in an end index past the end of the + * array + * @param endIndex + * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of + * the array + * @return the joined String, {@code null} if null array input + * @since 3.2 + */ + public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + buf.append(array[i]); + } + return buf.toString(); + } + + + /** + *

              Joins the elements of the provided array into a single String + * containing the provided list of elements.

              + * + *

              No delimiter is added before or after the list. + * A {@code null} separator is the same as an empty String (""). + * Null objects or empty strings within the array are represented by + * empty strings.

              + * + *
              +     * StringUtils.join(null, *)                = null
              +     * StringUtils.join([], *)                  = ""
              +     * StringUtils.join([null], *)              = ""
              +     * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
              +     * StringUtils.join(["a", "b", "c"], null)  = "abc"
              +     * StringUtils.join(["a", "b", "c"], "")    = "abc"
              +     * StringUtils.join([null, "", "a"], ',')   = ",,a"
              +     * 
              + * + * @param array the array of values to join together, may be null + * @param separator the separator character to use, null treated as "" + * @return the joined String, {@code null} if null array input + */ + public static String join(final Object[] array, final String separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + *

              Joins the elements of the provided array into a single String + * containing the provided list of elements.

              + * + *

              No delimiter is added before or after the list. + * A {@code null} separator is the same as an empty String (""). + * Null objects or empty strings within the array are represented by + * empty strings.

              + * + *
              +     * StringUtils.join(null, *, *, *)                = null
              +     * StringUtils.join([], *, *, *)                  = ""
              +     * StringUtils.join([null], *, *, *)              = ""
              +     * StringUtils.join(["a", "b", "c"], "--", 0, 3)  = "a--b--c"
              +     * StringUtils.join(["a", "b", "c"], "--", 1, 3)  = "b--c"
              +     * StringUtils.join(["a", "b", "c"], "--", 2, 3)  = "c"
              +     * StringUtils.join(["a", "b", "c"], "--", 2, 2)  = ""
              +     * StringUtils.join(["a", "b", "c"], null, 0, 3)  = "abc"
              +     * StringUtils.join(["a", "b", "c"], "", 0, 3)    = "abc"
              +     * StringUtils.join([null, "", "a"], ',', 0, 3)   = ",,a"
              +     * 
              + * + * @param array the array of values to join together, may be null + * @param separator the separator character to use, null treated as "" + * @param startIndex the first index to start joining from. + * @param endIndex the index to stop joining from (exclusive). + * @return the joined String, {@code null} if null array input; or the empty string + * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by + * {@code endIndex - startIndex} + * @throws ArrayIndexOutOfBoundsException ife
              + * {@code startIndex < 0} or
              + * {@code startIndex >= array.length()} or
              + * {@code endIndex < 0} or
              + * {@code endIndex > array.length()} + */ + public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) { + if (array == null) { + return null; + } + if (separator == null) { + separator = EMPTY; + } + + // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator)) + // (Assuming that all Strings are roughly equally long) + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + + final StringBuilder buf = new StringBuilder(noOfItems * 16); + + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + if (array[i] != null) { + buf.append(array[i]); + } + } + return buf.toString(); + } + + /** + *

              Joins the elements of the provided {@code Iterator} into + * a single String containing the provided elements.

              + * + *

              No delimiter is added before or after the list. Null objects or empty + * strings within the iteration are represented by empty strings.

              + * + *

              See the examples here: {@link #join(Object[],char)}.

              + * + * @param iterator the {@code Iterator} of values to join together, may be null + * @param separator the separator character to use + * @return the joined String, {@code null} if null iterator input + * @since 2.0 + */ + public static String join(final Iterator iterator, final char separator) { + + // handle null, zero and one elements before building a buffer + if (iterator == null) { + return null; + } + if (!iterator.hasNext()) { + return EMPTY; + } + final Object first = iterator.next(); + if (!iterator.hasNext()) { + final String result = Objects.toString(first, ""); + return result; + } + + // two or more elements + final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small + if (first != null) { + buf.append(first); + } + + while (iterator.hasNext()) { + buf.append(separator); + final Object obj = iterator.next(); + if (obj != null) { + buf.append(obj); + } + } + + return buf.toString(); + } + + /** + *

              Joins the elements of the provided {@code Iterator} into + * a single String containing the provided elements.

              + * + *

              No delimiter is added before or after the list. + * A {@code null} separator is the same as an empty String ("").

              + * + *

              See the examples here: {@link #join(Object[],String)}.

              + * + * @param iterator the {@code Iterator} of values to join together, may be null + * @param separator the separator character to use, null treated as "" + * @return the joined String, {@code null} if null iterator input + */ + public static String join(final Iterator iterator, final String separator) { + + // handle null, zero and one elements before building a buffer + if (iterator == null) { + return null; + } + if (!iterator.hasNext()) { + return EMPTY; + } + final Object first = iterator.next(); + if (!iterator.hasNext()) { + final String result = Objects.toString(first, ""); + return result; + } + + // two or more elements + final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small + if (first != null) { + buf.append(first); + } + + while (iterator.hasNext()) { + if (separator != null) { + buf.append(separator); + } + final Object obj = iterator.next(); + if (obj != null) { + buf.append(obj); + } + } + return buf.toString(); + } + + /** + *

              Joins the elements of the provided {@code Iterable} into + * a single String containing the provided elements.

              + * + *

              No delimiter is added before or after the list. Null objects or empty + * strings within the iteration are represented by empty strings.

              + * + *

              See the examples here: {@link #join(Object[],char)}.

              + * + * @param iterable the {@code Iterable} providing the values to join together, may be null + * @param separator the separator character to use + * @return the joined String, {@code null} if null iterator input + * @since 2.3 + */ + public static String join(final Iterable iterable, final char separator) { + if (iterable == null) { + return null; + } + return join(iterable.iterator(), separator); + } + + /** + *

              Joins the elements of the provided {@code Iterable} into + * a single String containing the provided elements.

              + * + *

              No delimiter is added before or after the list. + * A {@code null} separator is the same as an empty String ("").

              + * + *

              See the examples here: {@link #join(Object[],String)}.

              + * + * @param iterable the {@code Iterable} providing the values to join together, may be null + * @param separator the separator character to use, null treated as "" + * @return the joined String, {@code null} if null iterator input + * @since 2.3 + */ + public static String join(final Iterable iterable, final String separator) { + if (iterable == null) { + return null; + } + return join(iterable.iterator(), separator); + } + + /** + *

              Joins the elements of the provided varargs into a + * single String containing the provided elements.

              + * + *

              No delimiter is added before or after the list. + * {@code null} elements and separator are treated as empty Strings ("").

              + * + *
              +     * StringUtils.joinWith(",", {"a", "b"})        = "a,b"
              +     * StringUtils.joinWith(",", {"a", "b",""})     = "a,b,"
              +     * StringUtils.joinWith(",", {"a", null, "b"})  = "a,,b"
              +     * StringUtils.joinWith(null, {"a", "b"})       = "ab"
              +     * 
              + * + * @param separator the separator character to use, null treated as "" + * @param objects the varargs providing the values to join together. {@code null} elements are treated as "" + * @return the joined String. + * @throws java.lang.IllegalArgumentException if a null varargs is provided + * @since 3.5 + */ + public static String joinWith(final String separator, final Object... objects) { + if (objects == null) { + throw new IllegalArgumentException("Object varargs must not be null"); + } + + final String sanitizedSeparator = defaultString(separator, StringUtils.EMPTY); + + final StringBuilder result = new StringBuilder(); + + final Iterator iterator = Arrays.asList(objects).iterator(); + while (iterator.hasNext()) { + final String value = Objects.toString(iterator.next(), ""); + result.append(value); + + if (iterator.hasNext()) { + result.append(sanitizedSeparator); + } + } + + return result.toString(); + } + + // Delete + //----------------------------------------------------------------------- + /** + *

              Deletes all whitespaces from a String as defined by + * {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.deleteWhitespace(null)         = null
              +     * StringUtils.deleteWhitespace("")           = ""
              +     * StringUtils.deleteWhitespace("abc")        = "abc"
              +     * StringUtils.deleteWhitespace("   ab  c  ") = "abc"
              +     * 
              + * + * @param str the String to delete whitespace from, may be null + * @return the String without whitespaces, {@code null} if null String input + */ + public static String deleteWhitespace(final String str) { + if (isEmpty(str)) { + return str; + } + final int sz = str.length(); + final char[] chs = new char[sz]; + int count = 0; + for (int i = 0; i < sz; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + chs[count++] = str.charAt(i); + } + } + if (count == sz) { + return str; + } + return new String(chs, 0, count); + } + + // Remove + //----------------------------------------------------------------------- + /** + *

              Removes a substring only if it is at the beginning of a source string, + * otherwise returns the source string.

              + * + *

              A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string. + * A {@code null} search string will return the source string.

              + * + *
              +     * StringUtils.removeStart(null, *)      = null
              +     * StringUtils.removeStart("", *)        = ""
              +     * StringUtils.removeStart(*, null)      = *
              +     * StringUtils.removeStart("www.domain.com", "www.")   = "domain.com"
              +     * StringUtils.removeStart("domain.com", "www.")       = "domain.com"
              +     * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
              +     * StringUtils.removeStart("abc", "")    = "abc"
              +     * 
              + * + * @param str the source String to search, may be null + * @param remove the String to search for and remove, may be null + * @return the substring with the string removed if found, + * {@code null} if null String input + * @since 2.1 + */ + public static String removeStart(final String str, final String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + if (str.startsWith(remove)){ + return str.substring(remove.length()); + } + return str; + } + + /** + *

              Case insensitive removal of a substring if it is at the beginning of a source string, + * otherwise returns the source string.

              + * + *

              A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string. + * A {@code null} search string will return the source string.

              + * + *
              +     * StringUtils.removeStartIgnoreCase(null, *)      = null
              +     * StringUtils.removeStartIgnoreCase("", *)        = ""
              +     * StringUtils.removeStartIgnoreCase(*, null)      = *
              +     * StringUtils.removeStartIgnoreCase("www.domain.com", "www.")   = "domain.com"
              +     * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.")   = "domain.com"
              +     * StringUtils.removeStartIgnoreCase("domain.com", "www.")       = "domain.com"
              +     * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
              +     * StringUtils.removeStartIgnoreCase("abc", "")    = "abc"
              +     * 
              + * + * @param str the source String to search, may be null + * @param remove the String to search for (case insensitive) and remove, may be null + * @return the substring with the string removed if found, + * {@code null} if null String input + * @since 2.4 + */ + public static String removeStartIgnoreCase(final String str, final String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + if (startsWithIgnoreCase(str, remove)) { + return str.substring(remove.length()); + } + return str; + } + + /** + *

              Removes a substring only if it is at the end of a source string, + * otherwise returns the source string.

              + * + *

              A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string. + * A {@code null} search string will return the source string.

              + * + *
              +     * StringUtils.removeEnd(null, *)      = null
              +     * StringUtils.removeEnd("", *)        = ""
              +     * StringUtils.removeEnd(*, null)      = *
              +     * StringUtils.removeEnd("www.domain.com", ".com.")  = "www.domain.com"
              +     * StringUtils.removeEnd("www.domain.com", ".com")   = "www.domain"
              +     * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
              +     * StringUtils.removeEnd("abc", "")    = "abc"
              +     * 
              + * + * @param str the source String to search, may be null + * @param remove the String to search for and remove, may be null + * @return the substring with the string removed if found, + * {@code null} if null String input + * @since 2.1 + */ + public static String removeEnd(final String str, final String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + if (str.endsWith(remove)) { + return str.substring(0, str.length() - remove.length()); + } + return str; + } + + /** + *

              Case insensitive removal of a substring if it is at the end of a source string, + * otherwise returns the source string.

              + * + *

              A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string. + * A {@code null} search string will return the source string.

              + * + *
              +     * StringUtils.removeEndIgnoreCase(null, *)      = null
              +     * StringUtils.removeEndIgnoreCase("", *)        = ""
              +     * StringUtils.removeEndIgnoreCase(*, null)      = *
              +     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.")  = "www.domain.com"
              +     * StringUtils.removeEndIgnoreCase("www.domain.com", ".com")   = "www.domain"
              +     * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
              +     * StringUtils.removeEndIgnoreCase("abc", "")    = "abc"
              +     * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
              +     * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
              +     * 
              + * + * @param str the source String to search, may be null + * @param remove the String to search for (case insensitive) and remove, may be null + * @return the substring with the string removed if found, + * {@code null} if null String input + * @since 2.4 + */ + public static String removeEndIgnoreCase(final String str, final String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + if (endsWithIgnoreCase(str, remove)) { + return str.substring(0, str.length() - remove.length()); + } + return str; + } + + /** + *

              Removes all occurrences of a substring from within the source string.

              + * + *

              A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string. + * A {@code null} remove string will return the source string. + * An empty ("") remove string will return the source string.

              + * + *
              +     * StringUtils.remove(null, *)        = null
              +     * StringUtils.remove("", *)          = ""
              +     * StringUtils.remove(*, null)        = *
              +     * StringUtils.remove(*, "")          = *
              +     * StringUtils.remove("queued", "ue") = "qd"
              +     * StringUtils.remove("queued", "zz") = "queued"
              +     * 
              + * + * @param str the source String to search, may be null + * @param remove the String to search for and remove, may be null + * @return the substring with the string removed if found, + * {@code null} if null String input + * @since 2.1 + */ + public static String remove(final String str, final String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + return replace(str, remove, EMPTY, -1); + } + + /** + *

              + * Case insensitive removal of all occurrences of a substring from within + * the source string. + *

              + * + *

              + * A {@code null} source string will return {@code null}. An empty ("") + * source string will return the empty string. A {@code null} remove string + * will return the source string. An empty ("") remove string will return + * the source string. + *

              + * + *
              +     * StringUtils.removeIgnoreCase(null, *)        = null
              +     * StringUtils.removeIgnoreCase("", *)          = ""
              +     * StringUtils.removeIgnoreCase(*, null)        = *
              +     * StringUtils.removeIgnoreCase(*, "")          = *
              +     * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
              +     * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
              +     * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
              +     * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
              +     * 
              + * + * @param str + * the source String to search, may be null + * @param remove + * the String to search for (case insensitive) and remove, may be + * null + * @return the substring with the string removed if found, {@code null} if + * null String input + * @since 3.5 + */ + public static String removeIgnoreCase(final String str, final String remove) { + if (isEmpty(str) || isEmpty(remove)) { + return str; + } + return replaceIgnoreCase(str, remove, EMPTY, -1); + } + + /** + *

              Removes all occurrences of a character from within the source string.

              + * + *

              A {@code null} source string will return {@code null}. + * An empty ("") source string will return the empty string.

              + * + *
              +     * StringUtils.remove(null, *)       = null
              +     * StringUtils.remove("", *)         = ""
              +     * StringUtils.remove("queued", 'u') = "qeed"
              +     * StringUtils.remove("queued", 'z') = "queued"
              +     * 
              + * + * @param str the source String to search, may be null + * @param remove the char to search for and remove, may be null + * @return the substring with the char removed if found, + * {@code null} if null String input + * @since 2.1 + */ + public static String remove(final String str, final char remove) { + if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) { + return str; + } + final char[] chars = str.toCharArray(); + int pos = 0; + for (int i = 0; i < chars.length; i++) { + if (chars[i] != remove) { + chars[pos++] = chars[i]; + } + } + return new String(chars, 0, pos); + } + + /** + *

              Removes each substring of the text String that matches the given regular expression.

              + * + * This method is a {@code null} safe equivalent to: + *
                + *
              • {@code text.replaceAll(regex, StringUtils.EMPTY)}
              • + *
              • {@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}
              • + *
              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *

              Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option + * is NOT automatically added. + * To use the DOTALL option prepend "(?s)" to the regex. + * DOTALL is also know as single-line mode in Perl.

              + * + *
              +     * StringUtils.removeAll(null, *)      = null
              +     * StringUtils.removeAll("any", null)  = "any"
              +     * StringUtils.removeAll("any", "")    = "any"
              +     * StringUtils.removeAll("any", ".*")  = ""
              +     * StringUtils.removeAll("any", ".+")  = ""
              +     * StringUtils.removeAll("abc", ".?")  = ""
              +     * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
              +     * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
              +     * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
              +     * 
              + * + * @param text text to remove from, may be null + * @param regex the regular expression to which this string is to be matched + * @return the text with any removes processed, + * {@code null} if null String input + * + * @throws java.util.regex.PatternSyntaxException + * if the regular expression's syntax is invalid + * + * @see #replaceAll(String, String, String) + * @see #removePattern(String, String) + * @see String#replaceAll(String, String) + * @see java.util.regex.Pattern + * @see java.util.regex.Pattern#DOTALL + * @since 3.5 + */ + public static String removeAll(final String text, final String regex) { + return replaceAll(text, regex, StringUtils.EMPTY); + } + + /** + *

              Removes the first substring of the text string that matches the given regular expression.

              + * + * This method is a {@code null} safe equivalent to: + *
                + *
              • {@code text.replaceFirst(regex, StringUtils.EMPTY)}
              • + *
              • {@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}
              • + *
              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *

              The {@link Pattern#DOTALL} option is NOT automatically added. + * To use the DOTALL option prepend "(?s)" to the regex. + * DOTALL is also know as single-line mode in Perl.

              + * + *
              +     * StringUtils.removeFirst(null, *)      = null
              +     * StringUtils.removeFirst("any", null)  = "any"
              +     * StringUtils.removeFirst("any", "")    = "any"
              +     * StringUtils.removeFirst("any", ".*")  = ""
              +     * StringUtils.removeFirst("any", ".+")  = ""
              +     * StringUtils.removeFirst("abc", ".?")  = "bc"
              +     * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
              +     * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
              +     * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
              +     * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
              +     * 
              + * + * @param text text to remove from, may be null + * @param regex the regular expression to which this string is to be matched + * @return the text with the first replacement processed, + * {@code null} if null String input + * + * @throws java.util.regex.PatternSyntaxException + * if the regular expression's syntax is invalid + * + * @see #replaceFirst(String, String, String) + * @see String#replaceFirst(String, String) + * @see java.util.regex.Pattern + * @see java.util.regex.Pattern#DOTALL + * @since 3.5 + */ + public static String removeFirst(final String text, final String regex) { + return replaceFirst(text, regex, StringUtils.EMPTY); + } + + // Replacing + //----------------------------------------------------------------------- + /** + *

              Replaces a String with another String inside a larger String, once.

              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.replaceOnce(null, *, *)        = null
              +     * StringUtils.replaceOnce("", *, *)          = ""
              +     * StringUtils.replaceOnce("any", null, *)    = "any"
              +     * StringUtils.replaceOnce("any", *, null)    = "any"
              +     * StringUtils.replaceOnce("any", "", *)      = "any"
              +     * StringUtils.replaceOnce("aba", "a", null)  = "aba"
              +     * StringUtils.replaceOnce("aba", "a", "")    = "ba"
              +     * StringUtils.replaceOnce("aba", "a", "z")   = "zba"
              +     * 
              + * + * @see #replace(String text, String searchString, String replacement, int max) + * @param text text to search and replace in, may be null + * @param searchString the String to search for, may be null + * @param replacement the String to replace with, may be null + * @return the text with any replacements processed, + * {@code null} if null String input + */ + public static String replaceOnce(final String text, final String searchString, final String replacement) { + return replace(text, searchString, replacement, 1); + } + + /** + *

              Case insensitively replaces a String with another String inside a larger String, once.

              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.replaceOnceIgnoreCase(null, *, *)        = null
              +     * StringUtils.replaceOnceIgnoreCase("", *, *)          = ""
              +     * StringUtils.replaceOnceIgnoreCase("any", null, *)    = "any"
              +     * StringUtils.replaceOnceIgnoreCase("any", *, null)    = "any"
              +     * StringUtils.replaceOnceIgnoreCase("any", "", *)      = "any"
              +     * StringUtils.replaceOnceIgnoreCase("aba", "a", null)  = "aba"
              +     * StringUtils.replaceOnceIgnoreCase("aba", "a", "")    = "ba"
              +     * StringUtils.replaceOnceIgnoreCase("aba", "a", "z")   = "zba"
              +     * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
              +     * 
              + * + * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) + * @param text text to search and replace in, may be null + * @param searchString the String to search for (case insensitive), may be null + * @param replacement the String to replace with, may be null + * @return the text with any replacements processed, + * {@code null} if null String input + * @since 3.5 + */ + public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { + return replaceIgnoreCase(text, searchString, replacement, 1); + } + + /** + *

              Replaces each substring of the source String that matches the given regular expression with the given + * replacement using the {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in Perl.

              + * + * This call is a {@code null} safe equivalent to: + *
                + *
              • {@code source.replaceAll("(?s)" + regex, replacement)}
              • + *
              • {@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}
              • + *
              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.replacePattern(null, *, *)       = null
              +     * StringUtils.replacePattern("any", null, *)   = "any"
              +     * StringUtils.replacePattern("any", *, null)   = "any"
              +     * StringUtils.replacePattern("", "", "zzz")    = "zzz"
              +     * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
              +     * StringUtils.replacePattern("", ".+", "zzz")  = ""
              +     * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
              +     * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
              +     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
              +     * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
              +     * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
              +     * 
              + * + * @param source + * the source string + * @param regex + * the regular expression to which this string is to be matched + * @param replacement + * the string to be substituted for each match + * @return The resulting {@code String} + * @see #replaceAll(String, String, String) + * @see String#replaceAll(String, String) + * @see Pattern#DOTALL + * @since 3.2 + * @since 3.5 Changed {@code null} reference passed to this method is a no-op. + */ + public static String replacePattern(final String source, final String regex, final String replacement) { + if (source == null || regex == null || replacement == null) { + return source; + } + return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement); + } + + /** + *

              Removes each substring of the source String that matches the given regular expression using the DOTALL option. + *

              + * + * This call is a {@code null} safe equivalent to: + *
                + *
              • {@code source.replaceAll("(?s)" + regex, StringUtils.EMPTY)}
              • + *
              • {@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}
              • + *
              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.removePattern(null, *)       = null
              +     * StringUtils.removePattern("any", null)   = "any"
              +     * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
              +     * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
              +     * 
              + * + * @param source + * the source string + * @param regex + * the regular expression to which this string is to be matched + * @return The resulting {@code String} + * @see #replacePattern(String, String, String) + * @see String#replaceAll(String, String) + * @see Pattern#DOTALL + * @since 3.2 + * @since 3.5 Changed {@code null} reference passed to this method is a no-op. + */ + public static String removePattern(final String source, final String regex) { + return replacePattern(source, regex, StringUtils.EMPTY); + } + + /** + *

              Replaces each substring of the text String that matches the given regular expression + * with the given replacement.

              + * + * This method is a {@code null} safe equivalent to: + *
                + *
              • {@code text.replaceAll(regex, replacement)}
              • + *
              • {@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}
              • + *
              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *

              Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option + * is NOT automatically added. + * To use the DOTALL option prepend "(?s)" to the regex. + * DOTALL is also know as single-line mode in Perl.

              + * + *
              +     * StringUtils.replaceAll(null, *, *)       = null
              +     * StringUtils.replaceAll("any", null, *)   = "any"
              +     * StringUtils.replaceAll("any", *, null)   = "any"
              +     * StringUtils.replaceAll("", "", "zzz")    = "zzz"
              +     * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
              +     * StringUtils.replaceAll("", ".+", "zzz")  = ""
              +     * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
              +     * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
              +     * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
              +     * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
              +     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
              +     * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
              +     * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
              +     * 
              + * + * @param text text to search and replace in, may be null + * @param regex the regular expression to which this string is to be matched + * @param replacement the string to be substituted for each match + * @return the text with any replacements processed, + * {@code null} if null String input + * + * @throws java.util.regex.PatternSyntaxException + * if the regular expression's syntax is invalid + * + * @see #replacePattern(String, String, String) + * @see String#replaceAll(String, String) + * @see java.util.regex.Pattern + * @see java.util.regex.Pattern#DOTALL + * @since 3.5 + */ + public static String replaceAll(final String text, final String regex, final String replacement) { + if (text == null || regex == null|| replacement == null ) { + return text; + } + return text.replaceAll(regex, replacement); + } + + /** + *

              Replaces the first substring of the text string that matches the given regular expression + * with the given replacement.

              + * + * This method is a {@code null} safe equivalent to: + *
                + *
              • {@code text.replaceFirst(regex, replacement)}
              • + *
              • {@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}
              • + *
              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *

              The {@link Pattern#DOTALL} option is NOT automatically added. + * To use the DOTALL option prepend "(?s)" to the regex. + * DOTALL is also know as single-line mode in Perl.

              + * + *
              +     * StringUtils.replaceFirst(null, *, *)       = null
              +     * StringUtils.replaceFirst("any", null, *)   = "any"
              +     * StringUtils.replaceFirst("any", *, null)   = "any"
              +     * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
              +     * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
              +     * StringUtils.replaceFirst("", ".+", "zzz")  = ""
              +     * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
              +     * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
              +     * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
              +     * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
              +     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
              +     * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
              +     * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
              +     * 
              + * + * @param text text to search and replace in, may be null + * @param regex the regular expression to which this string is to be matched + * @param replacement the string to be substituted for the first match + * @return the text with the first replacement processed, + * {@code null} if null String input + * + * @throws java.util.regex.PatternSyntaxException + * if the regular expression's syntax is invalid + * + * @see String#replaceFirst(String, String) + * @see java.util.regex.Pattern + * @see java.util.regex.Pattern#DOTALL + * @since 3.5 + */ + public static String replaceFirst(final String text, final String regex, final String replacement) { + if (text == null || regex == null|| replacement == null ) { + return text; + } + return text.replaceFirst(regex, replacement); + } + + /** + *

              Replaces all occurrences of a String within another String.

              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.replace(null, *, *)        = null
              +     * StringUtils.replace("", *, *)          = ""
              +     * StringUtils.replace("any", null, *)    = "any"
              +     * StringUtils.replace("any", *, null)    = "any"
              +     * StringUtils.replace("any", "", *)      = "any"
              +     * StringUtils.replace("aba", "a", null)  = "aba"
              +     * StringUtils.replace("aba", "a", "")    = "b"
              +     * StringUtils.replace("aba", "a", "z")   = "zbz"
              +     * 
              + * + * @see #replace(String text, String searchString, String replacement, int max) + * @param text text to search and replace in, may be null + * @param searchString the String to search for, may be null + * @param replacement the String to replace it with, may be null + * @return the text with any replacements processed, + * {@code null} if null String input + */ + public static String replace(final String text, final String searchString, final String replacement) { + return replace(text, searchString, replacement, -1); + } + + /** + *

              Case insensitively replaces all occurrences of a String within another String.

              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +    * StringUtils.replaceIgnoreCase(null, *, *)        = null
              +    * StringUtils.replaceIgnoreCase("", *, *)          = ""
              +    * StringUtils.replaceIgnoreCase("any", null, *)    = "any"
              +    * StringUtils.replaceIgnoreCase("any", *, null)    = "any"
              +    * StringUtils.replaceIgnoreCase("any", "", *)      = "any"
              +    * StringUtils.replaceIgnoreCase("aba", "a", null)  = "aba"
              +    * StringUtils.replaceIgnoreCase("abA", "A", "")    = "b"
              +    * StringUtils.replaceIgnoreCase("aba", "A", "z")   = "zbz"
              +    * 
              + * + * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max) + * @param text text to search and replace in, may be null + * @param searchString the String to search for (case insensitive), may be null + * @param replacement the String to replace it with, may be null + * @return the text with any replacements processed, + * {@code null} if null String input + * @since 3.5 + */ + public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { + return replaceIgnoreCase(text, searchString, replacement, -1); + } + + /** + *

              Replaces a String with another String inside a larger String, + * for the first {@code max} values of the search String.

              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.replace(null, *, *, *)         = null
              +     * StringUtils.replace("", *, *, *)           = ""
              +     * StringUtils.replace("any", null, *, *)     = "any"
              +     * StringUtils.replace("any", *, null, *)     = "any"
              +     * StringUtils.replace("any", "", *, *)       = "any"
              +     * StringUtils.replace("any", *, *, 0)        = "any"
              +     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
              +     * StringUtils.replace("abaa", "a", "", -1)   = "b"
              +     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
              +     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
              +     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
              +     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
              +     * 
              + * + * @param text text to search and replace in, may be null + * @param searchString the String to search for, may be null + * @param replacement the String to replace it with, may be null + * @param max maximum number of values to replace, or {@code -1} if no maximum + * @return the text with any replacements processed, + * {@code null} if null String input + */ + public static String replace(final String text, final String searchString, final String replacement, final int max) { + return replace(text, searchString, replacement, max, false); + } + + /** + *

              Replaces a String with another String inside a larger String, + * for the first {@code max} values of the search String, + * case sensitively/insensisitively based on {@code ignoreCase} value.

              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.replace(null, *, *, *, false)         = null
              +     * StringUtils.replace("", *, *, *, false)           = ""
              +     * StringUtils.replace("any", null, *, *, false)     = "any"
              +     * StringUtils.replace("any", *, null, *, false)     = "any"
              +     * StringUtils.replace("any", "", *, *, false)       = "any"
              +     * StringUtils.replace("any", *, *, 0, false)        = "any"
              +     * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
              +     * StringUtils.replace("abaa", "a", "", -1, false)   = "b"
              +     * StringUtils.replace("abaa", "a", "z", 0, false)   = "abaa"
              +     * StringUtils.replace("abaa", "A", "z", 1, false)   = "abaa"
              +     * StringUtils.replace("abaa", "A", "z", 1, true)   = "zbaa"
              +     * StringUtils.replace("abAa", "a", "z", 2, true)   = "zbza"
              +     * StringUtils.replace("abAa", "a", "z", -1, true)  = "zbzz"
              +     * 
              + * + * @param text text to search and replace in, may be null + * @param searchString the String to search for (case insensitive), may be null + * @param replacement the String to replace it with, may be null + * @param max maximum number of values to replace, or {@code -1} if no maximum + * @param ignoreCase if true replace is case insensitive, otherwise case sensitive + * @return the text with any replacements processed, + * {@code null} if null String input + */ + private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) { + if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { + return text; + } + String searchText = text; + if (ignoreCase) { + searchText = text.toLowerCase(); + searchString = searchString.toLowerCase(); + } + int start = 0; + int end = searchText.indexOf(searchString, start); + if (end == INDEX_NOT_FOUND) { + return text; + } + final int replLength = searchString.length(); + int increase = replacement.length() - replLength; + increase = increase < 0 ? 0 : increase; + increase *= max < 0 ? 16 : max > 64 ? 64 : max; + final StringBuilder buf = new StringBuilder(text.length() + increase); + while (end != INDEX_NOT_FOUND) { + buf.append(text.substring(start, end)).append(replacement); + start = end + replLength; + if (--max == 0) { + break; + } + end = searchText.indexOf(searchString, start); + } + buf.append(text.substring(start)); + return buf.toString(); + } + + /** + *

              Case insensitively replaces a String with another String inside a larger String, + * for the first {@code max} values of the search String.

              + * + *

              A {@code null} reference passed to this method is a no-op.

              + * + *
              +     * StringUtils.replaceIgnoreCase(null, *, *, *)         = null
              +     * StringUtils.replaceIgnoreCase("", *, *, *)           = ""
              +     * StringUtils.replaceIgnoreCase("any", null, *, *)     = "any"
              +     * StringUtils.replaceIgnoreCase("any", *, null, *)     = "any"
              +     * StringUtils.replaceIgnoreCase("any", "", *, *)       = "any"
              +     * StringUtils.replaceIgnoreCase("any", *, *, 0)        = "any"
              +     * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
              +     * StringUtils.replaceIgnoreCase("abaa", "a", "", -1)   = "b"
              +     * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0)   = "abaa"
              +     * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1)   = "zbaa"
              +     * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2)   = "zbza"
              +     * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1)  = "zbzz"
              +     * 
              + * + * @param text text to search and replace in, may be null + * @param searchString the String to search for (case insensitive), may be null + * @param replacement the String to replace it with, may be null + * @param max maximum number of values to replace, or {@code -1} if no maximum + * @return the text with any replacements processed, + * {@code null} if null String input + * @since 3.5 + */ + public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { + return replace(text, searchString, replacement, max, true); + } + + /** + *

              + * Replaces all occurrences of Strings within another String. + *

              + * + *

              + * A {@code null} reference passed to this method is a no-op, or if + * any "search string" or "string to replace" is null, that replace will be + * ignored. This will not repeat. For repeating replaces, call the + * overloaded method. + *

              + * + *
              +     *  StringUtils.replaceEach(null, *, *)        = null
              +     *  StringUtils.replaceEach("", *, *)          = ""
              +     *  StringUtils.replaceEach("aba", null, null) = "aba"
              +     *  StringUtils.replaceEach("aba", new String[0], null) = "aba"
              +     *  StringUtils.replaceEach("aba", null, new String[0]) = "aba"
              +     *  StringUtils.replaceEach("aba", new String[]{"a"}, null)  = "aba"
              +     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""})  = "b"
              +     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"})  = "aba"
              +     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"})  = "wcte"
              +     *  (example of how it does not repeat)
              +     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"})  = "dcte"
              +     * 
              + * + * @param text + * text to search and replace in, no-op if null + * @param searchList + * the Strings to search for, no-op if null + * @param replacementList + * the Strings to replace them with, no-op if null + * @return the text with any replacements processed, {@code null} if + * null String input + * @throws IllegalArgumentException + * if the lengths of the arrays are not the same (null is ok, + * and/or size 0) + * @since 2.4 + */ + public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { + return replaceEach(text, searchList, replacementList, false, 0); + } + + /** + *

              + * Replaces all occurrences of Strings within another String. + *

              + * + *

              + * A {@code null} reference passed to this method is a no-op, or if + * any "search string" or "string to replace" is null, that replace will be + * ignored. + *

              + * + *
              +     *  StringUtils.replaceEachRepeatedly(null, *, *) = null
              +     *  StringUtils.replaceEachRepeatedly("", *, *) = ""
              +     *  StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
              +     *  StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
              +     *  StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
              +     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
              +     *  StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
              +     *  StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
              +     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
              +     *  (example of how it repeats)
              +     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
              +     *  StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
              +     * 
              + * + * @param text + * text to search and replace in, no-op if null + * @param searchList + * the Strings to search for, no-op if null + * @param replacementList + * the Strings to replace them with, no-op if null + * @return the text with any replacements processed, {@code null} if + * null String input + * @throws IllegalStateException + * if the search is repeating and there is an endless loop due + * to outputs of one being inputs to another + * @throws IllegalArgumentException + * if the lengths of the arrays are not the same (null is ok, + * and/or size 0) + * @since 2.4 + */ + public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { + // timeToLive should be 0 if not used or nothing to replace, else it's + // the length of the replace array + final int timeToLive = searchList == null ? 0 : searchList.length; + return replaceEach(text, searchList, replacementList, true, timeToLive); + } + + /** + *

              + * Replace all occurrences of Strings within another String. + * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and + * {@link #replaceEach(String, String[], String[])} + *

              + * + *

              + * A {@code null} reference passed to this method is a no-op, or if + * any "search string" or "string to replace" is null, that replace will be + * ignored. + *

              + * + *
              +     *  StringUtils.replaceEach(null, *, *, *, *) = null
              +     *  StringUtils.replaceEach("", *, *, *, *) = ""
              +     *  StringUtils.replaceEach("aba", null, null, *, *) = "aba"
              +     *  StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
              +     *  StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
              +     *  StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
              +     *  StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
              +     *  StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
              +     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
              +     *  (example of how it repeats)
              +     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
              +     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
              +     *  StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
              +     * 
              + * + * @param text + * text to search and replace in, no-op if null + * @param searchList + * the Strings to search for, no-op if null + * @param replacementList + * the Strings to replace them with, no-op if null + * @param repeat if true, then replace repeatedly + * until there are no more possible replacements or timeToLive < 0 + * @param timeToLive + * if less than 0 then there is a circular reference and endless + * loop + * @return the text with any replacements processed, {@code null} if + * null String input + * @throws IllegalStateException + * if the search is repeating and there is an endless loop due + * to outputs of one being inputs to another + * @throws IllegalArgumentException + * if the lengths of the arrays are not the same (null is ok, + * and/or size 0) + * @since 2.4 + */ + private static String replaceEach( + final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { + + // mchyzer Performance note: This creates very few new objects (one major goal) + // let me know if there are performance requests, we can create a harness to measure + + if (text == null || text.isEmpty() || searchList == null || + searchList.length == 0 || replacementList == null || replacementList.length == 0) { + return text; + } + + // if recursing, this shouldn't be less than 0 + if (timeToLive < 0) { + throw new IllegalStateException("Aborting to protect against StackOverflowError - " + + "output of one loop is the input of another"); + } + + final int searchLength = searchList.length; + final int replacementLength = replacementList.length; + + // make sure lengths are ok, these need to be equal + if (searchLength != replacementLength) { + throw new IllegalArgumentException("Search and Replace array lengths don't match: " + + searchLength + + " vs " + + replacementLength); + } + + // keep track of which still have matches + final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; + + // index on index that the match was found + int textIndex = -1; + int replaceIndex = -1; + int tempIndex = -1; + + // index of replace array that will replace the search string found + // NOTE: logic duplicated below START + for (int i = 0; i < searchLength; i++) { + if (noMoreMatchesForReplIndex[i] || searchList[i] == null || + searchList[i].isEmpty() || replacementList[i] == null) { + continue; + } + tempIndex = text.indexOf(searchList[i]); + + // see if we need to keep searching for this + if (tempIndex == -1) { + noMoreMatchesForReplIndex[i] = true; + } else { + if (textIndex == -1 || tempIndex < textIndex) { + textIndex = tempIndex; + replaceIndex = i; + } + } + } + // NOTE: logic mostly below END + + // no search strings found, we are done + if (textIndex == -1) { + return text; + } + + int start = 0; + + // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit + int increase = 0; + + // count the replacement text elements that are larger than their corresponding text being replaced + for (int i = 0; i < searchList.length; i++) { + if (searchList[i] == null || replacementList[i] == null) { + continue; + } + final int greater = replacementList[i].length() - searchList[i].length(); + if (greater > 0) { + increase += 3 * greater; // assume 3 matches + } + } + // have upper-bound at 20% increase, then let Java take over + increase = Math.min(increase, text.length() / 5); + + final StringBuilder buf = new StringBuilder(text.length() + increase); + + while (textIndex != -1) { + + for (int i = start; i < textIndex; i++) { + buf.append(text.charAt(i)); + } + buf.append(replacementList[replaceIndex]); + + start = textIndex + searchList[replaceIndex].length(); + + textIndex = -1; + replaceIndex = -1; + tempIndex = -1; + // find the next earliest match + // NOTE: logic mostly duplicated above START + for (int i = 0; i < searchLength; i++) { + if (noMoreMatchesForReplIndex[i] || searchList[i] == null || + searchList[i].isEmpty() || replacementList[i] == null) { + continue; + } + tempIndex = text.indexOf(searchList[i], start); + + // see if we need to keep searching for this + if (tempIndex == -1) { + noMoreMatchesForReplIndex[i] = true; + } else { + if (textIndex == -1 || tempIndex < textIndex) { + textIndex = tempIndex; + replaceIndex = i; + } + } + } + // NOTE: logic duplicated above END + + } + final int textLength = text.length(); + for (int i = start; i < textLength; i++) { + buf.append(text.charAt(i)); + } + final String result = buf.toString(); + if (!repeat) { + return result; + } + + return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); + } + + // Replace, character based + //----------------------------------------------------------------------- + /** + *

              Replaces all occurrences of a character in a String with another. + * This is a null-safe version of {@link String#replace(char, char)}.

              + * + *

              A {@code null} string input returns {@code null}. + * An empty ("") string input returns an empty string.

              + * + *
              +     * StringUtils.replaceChars(null, *, *)        = null
              +     * StringUtils.replaceChars("", *, *)          = ""
              +     * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
              +     * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
              +     * 
              + * + * @param str String to replace characters in, may be null + * @param searchChar the character to search for, may be null + * @param replaceChar the character to replace, may be null + * @return modified String, {@code null} if null string input + * @since 2.0 + */ + public static String replaceChars(final String str, final char searchChar, final char replaceChar) { + if (str == null) { + return null; + } + return str.replace(searchChar, replaceChar); + } + + /** + *

              Replaces multiple characters in a String in one go. + * This method can also be used to delete characters.

              + * + *

              For example:
              + * replaceChars("hello", "ho", "jy") = jelly.

              + * + *

              A {@code null} string input returns {@code null}. + * An empty ("") string input returns an empty string. + * A null or empty set of search characters returns the input string.

              + * + *

              The length of the search characters should normally equal the length + * of the replace characters. + * If the search characters is longer, then the extra search characters + * are deleted. + * If the search characters is shorter, then the extra replace characters + * are ignored.

              + * + *
              +     * StringUtils.replaceChars(null, *, *)           = null
              +     * StringUtils.replaceChars("", *, *)             = ""
              +     * StringUtils.replaceChars("abc", null, *)       = "abc"
              +     * StringUtils.replaceChars("abc", "", *)         = "abc"
              +     * StringUtils.replaceChars("abc", "b", null)     = "ac"
              +     * StringUtils.replaceChars("abc", "b", "")       = "ac"
              +     * StringUtils.replaceChars("abcba", "bc", "yz")  = "ayzya"
              +     * StringUtils.replaceChars("abcba", "bc", "y")   = "ayya"
              +     * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
              +     * 
              + * + * @param str String to replace characters in, may be null + * @param searchChars a set of characters to search for, may be null + * @param replaceChars a set of characters to replace, may be null + * @return modified String, {@code null} if null string input + * @since 2.0 + */ + public static String replaceChars(final String str, final String searchChars, String replaceChars) { + if (isEmpty(str) || isEmpty(searchChars)) { + return str; + } + if (replaceChars == null) { + replaceChars = EMPTY; + } + boolean modified = false; + final int replaceCharsLength = replaceChars.length(); + final int strLength = str.length(); + final StringBuilder buf = new StringBuilder(strLength); + for (int i = 0; i < strLength; i++) { + final char ch = str.charAt(i); + final int index = searchChars.indexOf(ch); + if (index >= 0) { + modified = true; + if (index < replaceCharsLength) { + buf.append(replaceChars.charAt(index)); + } + } else { + buf.append(ch); + } + } + if (modified) { + return buf.toString(); + } + return str; + } + + // Overlay + //----------------------------------------------------------------------- + /** + *

              Overlays part of a String with another String.

              + * + *

              A {@code null} string input returns {@code null}. + * A negative index is treated as zero. + * An index greater than the string length is treated as the string length. + * The start index is always the smaller of the two indices.

              + * + *
              +     * StringUtils.overlay(null, *, *, *)            = null
              +     * StringUtils.overlay("", "abc", 0, 0)          = "abc"
              +     * StringUtils.overlay("abcdef", null, 2, 4)     = "abef"
              +     * StringUtils.overlay("abcdef", "", 2, 4)       = "abef"
              +     * StringUtils.overlay("abcdef", "", 4, 2)       = "abef"
              +     * StringUtils.overlay("abcdef", "zzzz", 2, 4)   = "abzzzzef"
              +     * StringUtils.overlay("abcdef", "zzzz", 4, 2)   = "abzzzzef"
              +     * StringUtils.overlay("abcdef", "zzzz", -1, 4)  = "zzzzef"
              +     * StringUtils.overlay("abcdef", "zzzz", 2, 8)   = "abzzzz"
              +     * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
              +     * StringUtils.overlay("abcdef", "zzzz", 8, 10)  = "abcdefzzzz"
              +     * 
              + * + * @param str the String to do overlaying in, may be null + * @param overlay the String to overlay, may be null + * @param start the position to start overlaying at + * @param end the position to stop overlaying before + * @return overlayed String, {@code null} if null String input + * @since 2.0 + */ + public static String overlay(final String str, String overlay, int start, int end) { + if (str == null) { + return null; + } + if (overlay == null) { + overlay = EMPTY; + } + final int len = str.length(); + if (start < 0) { + start = 0; + } + if (start > len) { + start = len; + } + if (end < 0) { + end = 0; + } + if (end > len) { + end = len; + } + if (start > end) { + final int temp = start; + start = end; + end = temp; + } + return new StringBuilder(len + start - end + overlay.length() + 1) + .append(str.substring(0, start)) + .append(overlay) + .append(str.substring(end)) + .toString(); + } + + // Chomping + //----------------------------------------------------------------------- + /** + *

              Removes one newline from end of a String if it's there, + * otherwise leave it alone. A newline is "{@code \n}", + * "{@code \r}", or "{@code \r\n}".

              + * + *

              NOTE: This method changed in 2.0. + * It now more closely matches Perl chomp.

              + * + *
              +     * StringUtils.chomp(null)          = null
              +     * StringUtils.chomp("")            = ""
              +     * StringUtils.chomp("abc \r")      = "abc "
              +     * StringUtils.chomp("abc\n")       = "abc"
              +     * StringUtils.chomp("abc\r\n")     = "abc"
              +     * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
              +     * StringUtils.chomp("abc\n\r")     = "abc\n"
              +     * StringUtils.chomp("abc\n\rabc")  = "abc\n\rabc"
              +     * StringUtils.chomp("\r")          = ""
              +     * StringUtils.chomp("\n")          = ""
              +     * StringUtils.chomp("\r\n")        = ""
              +     * 
              + * + * @param str the String to chomp a newline from, may be null + * @return String without newline, {@code null} if null String input + */ + public static String chomp(final String str) { + if (isEmpty(str)) { + return str; + } + + if (str.length() == 1) { + final char ch = str.charAt(0); + if (ch == CharUtils.CR || ch == CharUtils.LF) { + return EMPTY; + } + return str; + } + + int lastIdx = str.length() - 1; + final char last = str.charAt(lastIdx); + + if (last == CharUtils.LF) { + if (str.charAt(lastIdx - 1) == CharUtils.CR) { + lastIdx--; + } + } else if (last != CharUtils.CR) { + lastIdx++; + } + return str.substring(0, lastIdx); + } + + /** + *

              Removes {@code separator} from the end of + * {@code str} if it's there, otherwise leave it alone.

              + * + *

              NOTE: This method changed in version 2.0. + * It now more closely matches Perl chomp. + * For the previous behavior, use {@link #substringBeforeLast(String, String)}. + * This method uses {@link String#endsWith(String)}.

              + * + *
              +     * StringUtils.chomp(null, *)         = null
              +     * StringUtils.chomp("", *)           = ""
              +     * StringUtils.chomp("foobar", "bar") = "foo"
              +     * StringUtils.chomp("foobar", "baz") = "foobar"
              +     * StringUtils.chomp("foo", "foo")    = ""
              +     * StringUtils.chomp("foo ", "foo")   = "foo "
              +     * StringUtils.chomp(" foo", "foo")   = " "
              +     * StringUtils.chomp("foo", "foooo")  = "foo"
              +     * StringUtils.chomp("foo", "")       = "foo"
              +     * StringUtils.chomp("foo", null)     = "foo"
              +     * 
              + * + * @param str the String to chomp from, may be null + * @param separator separator String, may be null + * @return String without trailing separator, {@code null} if null String input + * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead + */ + @Deprecated + public static String chomp(final String str, final String separator) { + return removeEnd(str,separator); + } + + // Chopping + //----------------------------------------------------------------------- + /** + *

              Remove the last character from a String.

              + * + *

              If the String ends in {@code \r\n}, then remove both + * of them.

              + * + *
              +     * StringUtils.chop(null)          = null
              +     * StringUtils.chop("")            = ""
              +     * StringUtils.chop("abc \r")      = "abc "
              +     * StringUtils.chop("abc\n")       = "abc"
              +     * StringUtils.chop("abc\r\n")     = "abc"
              +     * StringUtils.chop("abc")         = "ab"
              +     * StringUtils.chop("abc\nabc")    = "abc\nab"
              +     * StringUtils.chop("a")           = ""
              +     * StringUtils.chop("\r")          = ""
              +     * StringUtils.chop("\n")          = ""
              +     * StringUtils.chop("\r\n")        = ""
              +     * 
              + * + * @param str the String to chop last character from, may be null + * @return String without last character, {@code null} if null String input + */ + public static String chop(final String str) { + if (str == null) { + return null; + } + final int strLen = str.length(); + if (strLen < 2) { + return EMPTY; + } + final int lastIdx = strLen - 1; + final String ret = str.substring(0, lastIdx); + final char last = str.charAt(lastIdx); + if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) { + return ret.substring(0, lastIdx - 1); + } + return ret; + } + + // Conversion + //----------------------------------------------------------------------- + + // Padding + //----------------------------------------------------------------------- + /** + *

              Repeat a String {@code repeat} times to form a + * new String.

              + * + *
              +     * StringUtils.repeat(null, 2) = null
              +     * StringUtils.repeat("", 0)   = ""
              +     * StringUtils.repeat("", 2)   = ""
              +     * StringUtils.repeat("a", 3)  = "aaa"
              +     * StringUtils.repeat("ab", 2) = "abab"
              +     * StringUtils.repeat("a", -2) = ""
              +     * 
              + * + * @param str the String to repeat, may be null + * @param repeat number of times to repeat str, negative treated as zero + * @return a new String consisting of the original String repeated, + * {@code null} if null String input + */ + public static String repeat(final String str, final int repeat) { + // Performance tuned for 2.0 (JDK1.4) + + if (str == null) { + return null; + } + if (repeat <= 0) { + return EMPTY; + } + final int inputLength = str.length(); + if (repeat == 1 || inputLength == 0) { + return str; + } + if (inputLength == 1 && repeat <= PAD_LIMIT) { + return repeat(str.charAt(0), repeat); + } + + final int outputLength = inputLength * repeat; + switch (inputLength) { + case 1 : + return repeat(str.charAt(0), repeat); + case 2 : + final char ch0 = str.charAt(0); + final char ch1 = str.charAt(1); + final char[] output2 = new char[outputLength]; + for (int i = repeat * 2 - 2; i >= 0; i--, i--) { + output2[i] = ch0; + output2[i + 1] = ch1; + } + return new String(output2); + default : + final StringBuilder buf = new StringBuilder(outputLength); + for (int i = 0; i < repeat; i++) { + buf.append(str); + } + return buf.toString(); + } + } + + /** + *

              Repeat a String {@code repeat} times to form a + * new String, with a String separator injected each time.

              + * + *
              +     * StringUtils.repeat(null, null, 2) = null
              +     * StringUtils.repeat(null, "x", 2)  = null
              +     * StringUtils.repeat("", null, 0)   = ""
              +     * StringUtils.repeat("", "", 2)     = ""
              +     * StringUtils.repeat("", "x", 3)    = "xxx"
              +     * StringUtils.repeat("?", ", ", 3)  = "?, ?, ?"
              +     * 
              + * + * @param str the String to repeat, may be null + * @param separator the String to inject, may be null + * @param repeat number of times to repeat str, negative treated as zero + * @return a new String consisting of the original String repeated, + * {@code null} if null String input + * @since 2.5 + */ + public static String repeat(final String str, final String separator, final int repeat) { + if(str == null || separator == null) { + return repeat(str, repeat); + } + // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it + final String result = repeat(str + separator, repeat); + return removeEnd(result, separator); + } + + /** + *

              Returns padding using the specified delimiter repeated + * to a given length.

              + * + *
              +     * StringUtils.repeat('e', 0)  = ""
              +     * StringUtils.repeat('e', 3)  = "eee"
              +     * StringUtils.repeat('e', -2) = ""
              +     * 
              + * + *

              Note: this method doesn't not support padding with + * Unicode Supplementary Characters + * as they require a pair of {@code char}s to be represented. + * If you are needing to support full I18N of your applications + * consider using {@link #repeat(String, int)} instead. + *

              + * + * @param ch character to repeat + * @param repeat number of times to repeat char, negative treated as zero + * @return String with repeated character + * @see #repeat(String, int) + */ + public static String repeat(final char ch, final int repeat) { + if (repeat <= 0) { + return EMPTY; + } + final char[] buf = new char[repeat]; + for (int i = repeat - 1; i >= 0; i--) { + buf[i] = ch; + } + return new String(buf); + } + + /** + *

              Right pad a String with spaces (' ').

              + * + *

              The String is padded to the size of {@code size}.

              + * + *
              +     * StringUtils.rightPad(null, *)   = null
              +     * StringUtils.rightPad("", 3)     = "   "
              +     * StringUtils.rightPad("bat", 3)  = "bat"
              +     * StringUtils.rightPad("bat", 5)  = "bat  "
              +     * StringUtils.rightPad("bat", 1)  = "bat"
              +     * StringUtils.rightPad("bat", -1) = "bat"
              +     * 
              + * + * @param str the String to pad out, may be null + * @param size the size to pad to + * @return right padded String or original String if no padding is necessary, + * {@code null} if null String input + */ + public static String rightPad(final String str, final int size) { + return rightPad(str, size, ' '); + } + + /** + *

              Right pad a String with a specified character.

              + * + *

              The String is padded to the size of {@code size}.

              + * + *
              +     * StringUtils.rightPad(null, *, *)     = null
              +     * StringUtils.rightPad("", 3, 'z')     = "zzz"
              +     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
              +     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
              +     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
              +     * StringUtils.rightPad("bat", -1, 'z') = "bat"
              +     * 
              + * + * @param str the String to pad out, may be null + * @param size the size to pad to + * @param padChar the character to pad with + * @return right padded String or original String if no padding is necessary, + * {@code null} if null String input + * @since 2.0 + */ + public static String rightPad(final String str, final int size, final char padChar) { + if (str == null) { + return null; + } + final int pads = size - str.length(); + if (pads <= 0) { + return str; // returns original String when possible + } + if (pads > PAD_LIMIT) { + return rightPad(str, size, String.valueOf(padChar)); + } + return str.concat(repeat(padChar, pads)); + } + + /** + *

              Right pad a String with a specified String.

              + * + *

              The String is padded to the size of {@code size}.

              + * + *
              +     * StringUtils.rightPad(null, *, *)      = null
              +     * StringUtils.rightPad("", 3, "z")      = "zzz"
              +     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
              +     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
              +     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
              +     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
              +     * StringUtils.rightPad("bat", -1, "yz") = "bat"
              +     * StringUtils.rightPad("bat", 5, null)  = "bat  "
              +     * StringUtils.rightPad("bat", 5, "")    = "bat  "
              +     * 
              + * + * @param str the String to pad out, may be null + * @param size the size to pad to + * @param padStr the String to pad with, null or empty treated as single space + * @return right padded String or original String if no padding is necessary, + * {@code null} if null String input + */ + public static String rightPad(final String str, final int size, String padStr) { + if (str == null) { + return null; + } + if (isEmpty(padStr)) { + padStr = SPACE; + } + final int padLen = padStr.length(); + final int strLen = str.length(); + final int pads = size - strLen; + if (pads <= 0) { + return str; // returns original String when possible + } + if (padLen == 1 && pads <= PAD_LIMIT) { + return rightPad(str, size, padStr.charAt(0)); + } + + if (pads == padLen) { + return str.concat(padStr); + } else if (pads < padLen) { + return str.concat(padStr.substring(0, pads)); + } else { + final char[] padding = new char[pads]; + final char[] padChars = padStr.toCharArray(); + for (int i = 0; i < pads; i++) { + padding[i] = padChars[i % padLen]; + } + return str.concat(new String(padding)); + } + } + + /** + *

              Left pad a String with spaces (' ').

              + * + *

              The String is padded to the size of {@code size}.

              + * + *
              +     * StringUtils.leftPad(null, *)   = null
              +     * StringUtils.leftPad("", 3)     = "   "
              +     * StringUtils.leftPad("bat", 3)  = "bat"
              +     * StringUtils.leftPad("bat", 5)  = "  bat"
              +     * StringUtils.leftPad("bat", 1)  = "bat"
              +     * StringUtils.leftPad("bat", -1) = "bat"
              +     * 
              + * + * @param str the String to pad out, may be null + * @param size the size to pad to + * @return left padded String or original String if no padding is necessary, + * {@code null} if null String input + */ + public static String leftPad(final String str, final int size) { + return leftPad(str, size, ' '); + } + + /** + *

              Left pad a String with a specified character.

              + * + *

              Pad to a size of {@code size}.

              + * + *
              +     * StringUtils.leftPad(null, *, *)     = null
              +     * StringUtils.leftPad("", 3, 'z')     = "zzz"
              +     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
              +     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
              +     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
              +     * StringUtils.leftPad("bat", -1, 'z') = "bat"
              +     * 
              + * + * @param str the String to pad out, may be null + * @param size the size to pad to + * @param padChar the character to pad with + * @return left padded String or original String if no padding is necessary, + * {@code null} if null String input + * @since 2.0 + */ + public static String leftPad(final String str, final int size, final char padChar) { + if (str == null) { + return null; + } + final int pads = size - str.length(); + if (pads <= 0) { + return str; // returns original String when possible + } + if (pads > PAD_LIMIT) { + return leftPad(str, size, String.valueOf(padChar)); + } + return repeat(padChar, pads).concat(str); + } + + /** + *

              Left pad a String with a specified String.

              + * + *

              Pad to a size of {@code size}.

              + * + *
              +     * StringUtils.leftPad(null, *, *)      = null
              +     * StringUtils.leftPad("", 3, "z")      = "zzz"
              +     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
              +     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
              +     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
              +     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
              +     * StringUtils.leftPad("bat", -1, "yz") = "bat"
              +     * StringUtils.leftPad("bat", 5, null)  = "  bat"
              +     * StringUtils.leftPad("bat", 5, "")    = "  bat"
              +     * 
              + * + * @param str the String to pad out, may be null + * @param size the size to pad to + * @param padStr the String to pad with, null or empty treated as single space + * @return left padded String or original String if no padding is necessary, + * {@code null} if null String input + */ + public static String leftPad(final String str, final int size, String padStr) { + if (str == null) { + return null; + } + if (isEmpty(padStr)) { + padStr = SPACE; + } + final int padLen = padStr.length(); + final int strLen = str.length(); + final int pads = size - strLen; + if (pads <= 0) { + return str; // returns original String when possible + } + if (padLen == 1 && pads <= PAD_LIMIT) { + return leftPad(str, size, padStr.charAt(0)); + } + + if (pads == padLen) { + return padStr.concat(str); + } else if (pads < padLen) { + return padStr.substring(0, pads).concat(str); + } else { + final char[] padding = new char[pads]; + final char[] padChars = padStr.toCharArray(); + for (int i = 0; i < pads; i++) { + padding[i] = padChars[i % padLen]; + } + return new String(padding).concat(str); + } + } + + /** + * Gets a CharSequence length or {@code 0} if the CharSequence is + * {@code null}. + * + * @param cs + * a CharSequence or {@code null} + * @return CharSequence length or {@code 0} if the CharSequence is + * {@code null}. + * @since 2.4 + * @since 3.0 Changed signature from length(String) to length(CharSequence) + */ + public static int length(final CharSequence cs) { + return cs == null ? 0 : cs.length(); + } + + // Centering + //----------------------------------------------------------------------- + /** + *

              Centers a String in a larger String of size {@code size} + * using the space character (' ').

              + * + *

              If the size is less than the String length, the String is returned. + * A {@code null} String returns {@code null}. + * A negative size is treated as zero.

              + * + *

              Equivalent to {@code center(str, size, " ")}.

              + * + *
              +     * StringUtils.center(null, *)   = null
              +     * StringUtils.center("", 4)     = "    "
              +     * StringUtils.center("ab", -1)  = "ab"
              +     * StringUtils.center("ab", 4)   = " ab "
              +     * StringUtils.center("abcd", 2) = "abcd"
              +     * StringUtils.center("a", 4)    = " a  "
              +     * 
              + * + * @param str the String to center, may be null + * @param size the int size of new String, negative treated as zero + * @return centered String, {@code null} if null String input + */ + public static String center(final String str, final int size) { + return center(str, size, ' '); + } + + /** + *

              Centers a String in a larger String of size {@code size}. + * Uses a supplied character as the value to pad the String with.

              + * + *

              If the size is less than the String length, the String is returned. + * A {@code null} String returns {@code null}. + * A negative size is treated as zero.

              + * + *
              +     * StringUtils.center(null, *, *)     = null
              +     * StringUtils.center("", 4, ' ')     = "    "
              +     * StringUtils.center("ab", -1, ' ')  = "ab"
              +     * StringUtils.center("ab", 4, ' ')   = " ab "
              +     * StringUtils.center("abcd", 2, ' ') = "abcd"
              +     * StringUtils.center("a", 4, ' ')    = " a  "
              +     * StringUtils.center("a", 4, 'y')    = "yayy"
              +     * 
              + * + * @param str the String to center, may be null + * @param size the int size of new String, negative treated as zero + * @param padChar the character to pad the new String with + * @return centered String, {@code null} if null String input + * @since 2.0 + */ + public static String center(String str, final int size, final char padChar) { + if (str == null || size <= 0) { + return str; + } + final int strLen = str.length(); + final int pads = size - strLen; + if (pads <= 0) { + return str; + } + str = leftPad(str, strLen + pads / 2, padChar); + str = rightPad(str, size, padChar); + return str; + } + + /** + *

              Centers a String in a larger String of size {@code size}. + * Uses a supplied String as the value to pad the String with.

              + * + *

              If the size is less than the String length, the String is returned. + * A {@code null} String returns {@code null}. + * A negative size is treated as zero.

              + * + *
              +     * StringUtils.center(null, *, *)     = null
              +     * StringUtils.center("", 4, " ")     = "    "
              +     * StringUtils.center("ab", -1, " ")  = "ab"
              +     * StringUtils.center("ab", 4, " ")   = " ab "
              +     * StringUtils.center("abcd", 2, " ") = "abcd"
              +     * StringUtils.center("a", 4, " ")    = " a  "
              +     * StringUtils.center("a", 4, "yz")   = "yayz"
              +     * StringUtils.center("abc", 7, null) = "  abc  "
              +     * StringUtils.center("abc", 7, "")   = "  abc  "
              +     * 
              + * + * @param str the String to center, may be null + * @param size the int size of new String, negative treated as zero + * @param padStr the String to pad the new String with, must not be null or empty + * @return centered String, {@code null} if null String input + * @throws IllegalArgumentException if padStr is {@code null} or empty + */ + public static String center(String str, final int size, String padStr) { + if (str == null || size <= 0) { + return str; + } + if (isEmpty(padStr)) { + padStr = SPACE; + } + final int strLen = str.length(); + final int pads = size - strLen; + if (pads <= 0) { + return str; + } + str = leftPad(str, strLen + pads / 2, padStr); + str = rightPad(str, size, padStr); + return str; + } + + // Case conversion + //----------------------------------------------------------------------- + /** + *

              Converts a String to upper case as per {@link String#toUpperCase()}.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.upperCase(null)  = null
              +     * StringUtils.upperCase("")    = ""
              +     * StringUtils.upperCase("aBc") = "ABC"
              +     * 
              + * + *

              Note: As described in the documentation for {@link String#toUpperCase()}, + * the result of this method is affected by the current locale. + * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} + * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).

              + * + * @param str the String to upper case, may be null + * @return the upper cased String, {@code null} if null String input + */ + public static String upperCase(final String str) { + if (str == null) { + return null; + } + return str.toUpperCase(); + } + + /** + *

              Converts a String to upper case as per {@link String#toUpperCase(Locale)}.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.upperCase(null, Locale.ENGLISH)  = null
              +     * StringUtils.upperCase("", Locale.ENGLISH)    = ""
              +     * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
              +     * 
              + * + * @param str the String to upper case, may be null + * @param locale the locale that defines the case transformation rules, must not be null + * @return the upper cased String, {@code null} if null String input + * @since 2.5 + */ + public static String upperCase(final String str, final Locale locale) { + if (str == null) { + return null; + } + return str.toUpperCase(locale); + } + + /** + *

              Converts a String to lower case as per {@link String#toLowerCase()}.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.lowerCase(null)  = null
              +     * StringUtils.lowerCase("")    = ""
              +     * StringUtils.lowerCase("aBc") = "abc"
              +     * 
              + * + *

              Note: As described in the documentation for {@link String#toLowerCase()}, + * the result of this method is affected by the current locale. + * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)} + * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).

              + * + * @param str the String to lower case, may be null + * @return the lower cased String, {@code null} if null String input + */ + public static String lowerCase(final String str) { + if (str == null) { + return null; + } + return str.toLowerCase(); + } + + /** + *

              Converts a String to lower case as per {@link String#toLowerCase(Locale)}.

              + * + *

              A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.lowerCase(null, Locale.ENGLISH)  = null
              +     * StringUtils.lowerCase("", Locale.ENGLISH)    = ""
              +     * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
              +     * 
              + * + * @param str the String to lower case, may be null + * @param locale the locale that defines the case transformation rules, must not be null + * @return the lower cased String, {@code null} if null String input + * @since 2.5 + */ + public static String lowerCase(final String str, final Locale locale) { + if (str == null) { + return null; + } + return str.toLowerCase(locale); + } + + /** + *

              Capitalizes a String changing the first character to title case as + * per {@link Character#toTitleCase(int)}. No other characters are changed.

              + * + *

              For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}. + * A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.capitalize(null)  = null
              +     * StringUtils.capitalize("")    = ""
              +     * StringUtils.capitalize("cat") = "Cat"
              +     * StringUtils.capitalize("cAt") = "CAt"
              +     * StringUtils.capitalize("'cat'") = "'cat'"
              +     * 
              + * + * @param str the String to capitalize, may be null + * @return the capitalized String, {@code null} if null String input + * @see org.apache.commons.lang3.text.WordUtils#capitalize(String) + * @see #uncapitalize(String) + * @since 2.0 + */ + public static String capitalize(final String str) { + int strLen; + if (str == null || (strLen = str.length()) == 0) { + return str; + } + + final int firstCodepoint = str.codePointAt(0); + final int newCodePoint = Character.toTitleCase(firstCodepoint); + if (firstCodepoint == newCodePoint) { + // already capitalized + return str; + } + + final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array + int outOffset = 0; + newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint + for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { + final int codepoint = str.codePointAt(inOffset); + newCodePoints[outOffset++] = codepoint; // copy the remaining ones + inOffset += Character.charCount(codepoint); + } + return new String(newCodePoints, 0, outOffset); + } + + /** + *

              Uncapitalizes a String, changing the first character to lower case as + * per {@link Character#toLowerCase(int)}. No other characters are changed.

              + * + *

              For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}. + * A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.uncapitalize(null)  = null
              +     * StringUtils.uncapitalize("")    = ""
              +     * StringUtils.uncapitalize("cat") = "cat"
              +     * StringUtils.uncapitalize("Cat") = "cat"
              +     * StringUtils.uncapitalize("CAT") = "cAT"
              +     * 
              + * + * @param str the String to uncapitalize, may be null + * @return the uncapitalized String, {@code null} if null String input + * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String) + * @see #capitalize(String) + * @since 2.0 + */ + public static String uncapitalize(final String str) { + int strLen; + if (str == null || (strLen = str.length()) == 0) { + return str; + } + + final int firstCodepoint = str.codePointAt(0); + final int newCodePoint = Character.toLowerCase(firstCodepoint); + if (firstCodepoint == newCodePoint) { + // already capitalized + return str; + } + + final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array + int outOffset = 0; + newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint + for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) { + final int codepoint = str.codePointAt(inOffset); + newCodePoints[outOffset++] = codepoint; // copy the remaining ones + inOffset += Character.charCount(codepoint); + } + return new String(newCodePoints, 0, outOffset); + } + + /** + *

              Swaps the case of a String changing upper and title case to + * lower case, and lower case to upper case.

              + * + *
                + *
              • Upper case character converts to Lower case
              • + *
              • Title case character converts to Lower case
              • + *
              • Lower case character converts to Upper case
              • + *
              + * + *

              For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}. + * A {@code null} input String returns {@code null}.

              + * + *
              +     * StringUtils.swapCase(null)                 = null
              +     * StringUtils.swapCase("")                   = ""
              +     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
              +     * 
              + * + *

              NOTE: This method changed in Lang version 2.0. + * It no longer performs a word based algorithm. + * If you only use ASCII, you will notice no change. + * That functionality is available in org.apache.commons.lang3.text.WordUtils.

              + * + * @param str the String to swap case, may be null + * @return the changed String, {@code null} if null String input + */ + public static String swapCase(final String str) { + if (StringUtils.isEmpty(str)) { + return str; + } + + final int strLen = str.length(); + final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array + int outOffset = 0; + for (int i = 0; i < strLen; ) { + final int oldCodepoint = str.codePointAt(i); + final int newCodePoint; + if (Character.isUpperCase(oldCodepoint)) { + newCodePoint = Character.toLowerCase(oldCodepoint); + } else if (Character.isTitleCase(oldCodepoint)) { + newCodePoint = Character.toLowerCase(oldCodepoint); + } else if (Character.isLowerCase(oldCodepoint)) { + newCodePoint = Character.toUpperCase(oldCodepoint); + } else { + newCodePoint = oldCodepoint; + } + newCodePoints[outOffset++] = newCodePoint; + i += Character.charCount(newCodePoint); + } + return new String(newCodePoints, 0, outOffset); + } + + // Count matches + //----------------------------------------------------------------------- + /** + *

              Counts how many times the substring appears in the larger string.

              + * + *

              A {@code null} or empty ("") String input returns {@code 0}.

              + * + *
              +     * StringUtils.countMatches(null, *)       = 0
              +     * StringUtils.countMatches("", *)         = 0
              +     * StringUtils.countMatches("abba", null)  = 0
              +     * StringUtils.countMatches("abba", "")    = 0
              +     * StringUtils.countMatches("abba", "a")   = 2
              +     * StringUtils.countMatches("abba", "ab")  = 1
              +     * StringUtils.countMatches("abba", "xxx") = 0
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param sub the substring to count, may be null + * @return the number of occurrences, 0 if either CharSequence is {@code null} + * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence) + */ + public static int countMatches(final CharSequence str, final CharSequence sub) { + if (isEmpty(str) || isEmpty(sub)) { + return 0; + } + int count = 0; + int idx = 0; + while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { + count++; + idx += sub.length(); + } + return count; + } + + /** + *

              Counts how many times the char appears in the given string.

              + * + *

              A {@code null} or empty ("") String input returns {@code 0}.

              + * + *
              +     * StringUtils.countMatches(null, *)       = 0
              +     * StringUtils.countMatches("", *)         = 0
              +     * StringUtils.countMatches("abba", 0)  = 0
              +     * StringUtils.countMatches("abba", 'a')   = 2
              +     * StringUtils.countMatches("abba", 'b')  = 2
              +     * StringUtils.countMatches("abba", 'x') = 0
              +     * 
              + * + * @param str the CharSequence to check, may be null + * @param ch the char to count + * @return the number of occurrences, 0 if the CharSequence is {@code null} + * @since 3.4 + */ + public static int countMatches(final CharSequence str, final char ch) { + if (isEmpty(str)) { + return 0; + } + int count = 0; + // We could also call str.toCharArray() for faster look ups but that would generate more garbage. + for (int i = 0; i < str.length(); i++) { + if (ch == str.charAt(i)) { + count++; + } + } + return count; + } + + // Character Tests + //----------------------------------------------------------------------- + /** + *

              Checks if the CharSequence contains only Unicode letters.

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code false}.

              + * + *
              +     * StringUtils.isAlpha(null)   = false
              +     * StringUtils.isAlpha("")     = false
              +     * StringUtils.isAlpha("  ")   = false
              +     * StringUtils.isAlpha("abc")  = true
              +     * StringUtils.isAlpha("ab2c") = false
              +     * StringUtils.isAlpha("ab-c") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains letters, and is non-null + * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence) + * @since 3.0 Changed "" to return false and not true + */ + public static boolean isAlpha(final CharSequence cs) { + if (isEmpty(cs)) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isLetter(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only Unicode letters and + * space (' ').

              + * + *

              {@code null} will return {@code false} + * An empty CharSequence (length()=0) will return {@code true}.

              + * + *
              +     * StringUtils.isAlphaSpace(null)   = false
              +     * StringUtils.isAlphaSpace("")     = true
              +     * StringUtils.isAlphaSpace("  ")   = true
              +     * StringUtils.isAlphaSpace("abc")  = true
              +     * StringUtils.isAlphaSpace("ab c") = true
              +     * StringUtils.isAlphaSpace("ab2c") = false
              +     * StringUtils.isAlphaSpace("ab-c") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains letters and space, + * and is non-null + * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence) + */ + public static boolean isAlphaSpace(final CharSequence cs) { + if (cs == null) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isLetter(cs.charAt(i)) == false && cs.charAt(i) != ' ') { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only Unicode letters or digits.

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code false}.

              + * + *
              +     * StringUtils.isAlphanumeric(null)   = false
              +     * StringUtils.isAlphanumeric("")     = false
              +     * StringUtils.isAlphanumeric("  ")   = false
              +     * StringUtils.isAlphanumeric("abc")  = true
              +     * StringUtils.isAlphanumeric("ab c") = false
              +     * StringUtils.isAlphanumeric("ab2c") = true
              +     * StringUtils.isAlphanumeric("ab-c") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains letters or digits, + * and is non-null + * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence) + * @since 3.0 Changed "" to return false and not true + */ + public static boolean isAlphanumeric(final CharSequence cs) { + if (isEmpty(cs)) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isLetterOrDigit(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only Unicode letters, digits + * or space ({@code ' '}).

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code true}.

              + * + *
              +     * StringUtils.isAlphanumericSpace(null)   = false
              +     * StringUtils.isAlphanumericSpace("")     = true
              +     * StringUtils.isAlphanumericSpace("  ")   = true
              +     * StringUtils.isAlphanumericSpace("abc")  = true
              +     * StringUtils.isAlphanumericSpace("ab c") = true
              +     * StringUtils.isAlphanumericSpace("ab2c") = true
              +     * StringUtils.isAlphanumericSpace("ab-c") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains letters, digits or space, + * and is non-null + * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence) + */ + public static boolean isAlphanumericSpace(final CharSequence cs) { + if (cs == null) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isLetterOrDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only ASCII printable characters.

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code true}.

              + * + *
              +     * StringUtils.isAsciiPrintable(null)     = false
              +     * StringUtils.isAsciiPrintable("")       = true
              +     * StringUtils.isAsciiPrintable(" ")      = true
              +     * StringUtils.isAsciiPrintable("Ceki")   = true
              +     * StringUtils.isAsciiPrintable("ab2c")   = true
              +     * StringUtils.isAsciiPrintable("!ab-c~") = true
              +     * StringUtils.isAsciiPrintable("\u0020") = true
              +     * StringUtils.isAsciiPrintable("\u0021") = true
              +     * StringUtils.isAsciiPrintable("\u007e") = true
              +     * StringUtils.isAsciiPrintable("\u007f") = false
              +     * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if every character is in the range + * 32 thru 126 + * @since 2.1 + * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence) + */ + public static boolean isAsciiPrintable(final CharSequence cs) { + if (cs == null) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only Unicode digits. + * A decimal point is not a Unicode digit and returns false.

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code false}.

              + * + *

              Note that the method does not allow for a leading sign, either positive or negative. + * Also, if a String passes the numeric test, it may still generate a NumberFormatException + * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range + * for int or long respectively.

              + * + *
              +     * StringUtils.isNumeric(null)   = false
              +     * StringUtils.isNumeric("")     = false
              +     * StringUtils.isNumeric("  ")   = false
              +     * StringUtils.isNumeric("123")  = true
              +     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
              +     * StringUtils.isNumeric("12 3") = false
              +     * StringUtils.isNumeric("ab2c") = false
              +     * StringUtils.isNumeric("12-3") = false
              +     * StringUtils.isNumeric("12.3") = false
              +     * StringUtils.isNumeric("-123") = false
              +     * StringUtils.isNumeric("+123") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains digits, and is non-null + * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence) + * @since 3.0 Changed "" to return false and not true + */ + public static boolean isNumeric(final CharSequence cs) { + if (isEmpty(cs)) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (!Character.isDigit(cs.charAt(i))) { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only Unicode digits or space + * ({@code ' '}). + * A decimal point is not a Unicode digit and returns false.

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code true}.

              + * + *
              +     * StringUtils.isNumericSpace(null)   = false
              +     * StringUtils.isNumericSpace("")     = true
              +     * StringUtils.isNumericSpace("  ")   = true
              +     * StringUtils.isNumericSpace("123")  = true
              +     * StringUtils.isNumericSpace("12 3") = true
              +     * StringUtils.isNumeric("\u0967\u0968\u0969")  = true
              +     * StringUtils.isNumeric("\u0967\u0968 \u0969")  = true
              +     * StringUtils.isNumericSpace("ab2c") = false
              +     * StringUtils.isNumericSpace("12-3") = false
              +     * StringUtils.isNumericSpace("12.3") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains digits or space, + * and is non-null + * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence) + */ + public static boolean isNumericSpace(final CharSequence cs) { + if (cs == null) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only whitespace.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code true}.

              + * + *
              +     * StringUtils.isWhitespace(null)   = false
              +     * StringUtils.isWhitespace("")     = true
              +     * StringUtils.isWhitespace("  ")   = true
              +     * StringUtils.isWhitespace("abc")  = false
              +     * StringUtils.isWhitespace("ab2c") = false
              +     * StringUtils.isWhitespace("ab-c") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains whitespace, and is non-null + * @since 2.0 + * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence) + */ + public static boolean isWhitespace(final CharSequence cs) { + if (cs == null) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isWhitespace(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only lowercase characters.

              + * + *

              {@code null} will return {@code false}. + * An empty CharSequence (length()=0) will return {@code false}.

              + * + *
              +     * StringUtils.isAllLowerCase(null)   = false
              +     * StringUtils.isAllLowerCase("")     = false
              +     * StringUtils.isAllLowerCase("  ")   = false
              +     * StringUtils.isAllLowerCase("abc")  = true
              +     * StringUtils.isAllLowerCase("abC")  = false
              +     * StringUtils.isAllLowerCase("ab c") = false
              +     * StringUtils.isAllLowerCase("ab1c") = false
              +     * StringUtils.isAllLowerCase("ab/c") = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains lowercase characters, and is non-null + * @since 2.5 + * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence) + */ + public static boolean isAllLowerCase(final CharSequence cs) { + if (cs == null || isEmpty(cs)) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isLowerCase(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + /** + *

              Checks if the CharSequence contains only uppercase characters.

              + * + *

              {@code null} will return {@code false}. + * An empty String (length()=0) will return {@code false}.

              + * + *
              +     * StringUtils.isAllUpperCase(null)   = false
              +     * StringUtils.isAllUpperCase("")     = false
              +     * StringUtils.isAllUpperCase("  ")   = false
              +     * StringUtils.isAllUpperCase("ABC")  = true
              +     * StringUtils.isAllUpperCase("aBC")  = false
              +     * StringUtils.isAllUpperCase("A C")  = false
              +     * StringUtils.isAllUpperCase("A1C")  = false
              +     * StringUtils.isAllUpperCase("A/C")  = false
              +     * 
              + * + * @param cs the CharSequence to check, may be null + * @return {@code true} if only contains uppercase characters, and is non-null + * @since 2.5 + * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence) + */ + public static boolean isAllUpperCase(final CharSequence cs) { + if (cs == null || isEmpty(cs)) { + return false; + } + final int sz = cs.length(); + for (int i = 0; i < sz; i++) { + if (Character.isUpperCase(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + // Defaults + //----------------------------------------------------------------------- + /** + *

              Returns either the passed in String, + * or if the String is {@code null}, an empty String ("").

              + * + *
              +     * StringUtils.defaultString(null)  = ""
              +     * StringUtils.defaultString("")    = ""
              +     * StringUtils.defaultString("bat") = "bat"
              +     * 
              + * + * @see ObjectUtils#toString(Object) + * @see String#valueOf(Object) + * @param str the String to check, may be null + * @return the passed in String, or the empty String if it + * was {@code null} + */ + public static String defaultString(final String str) { + return str == null ? EMPTY : str; + } + + /** + *

              Returns either the passed in String, or if the String is + * {@code null}, the value of {@code defaultStr}.

              + * + *
              +     * StringUtils.defaultString(null, "NULL")  = "NULL"
              +     * StringUtils.defaultString("", "NULL")    = ""
              +     * StringUtils.defaultString("bat", "NULL") = "bat"
              +     * 
              + * + * @see ObjectUtils#toString(Object,String) + * @see String#valueOf(Object) + * @param str the String to check, may be null + * @param defaultStr the default String to return + * if the input is {@code null}, may be null + * @return the passed in String, or the default if it was {@code null} + */ + public static String defaultString(final String str, final String defaultStr) { + return str == null ? defaultStr : str; + } + + /** + *

              Returns either the passed in CharSequence, or if the CharSequence is + * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}.

              + * + *
              +     * StringUtils.defaultIfBlank(null, "NULL")  = "NULL"
              +     * StringUtils.defaultIfBlank("", "NULL")    = "NULL"
              +     * StringUtils.defaultIfBlank(" ", "NULL")   = "NULL"
              +     * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
              +     * StringUtils.defaultIfBlank("", null)      = null
              +     * 
              + * @param the specific kind of CharSequence + * @param str the CharSequence to check, may be null + * @param defaultStr the default CharSequence to return + * if the input is whitespace, empty ("") or {@code null}, may be null + * @return the passed in CharSequence, or the default + * @see StringUtils#defaultString(String, String) + */ + public static T defaultIfBlank(final T str, final T defaultStr) { + return isBlank(str) ? defaultStr : str; + } + + /** + *

              Returns either the passed in CharSequence, or if the CharSequence is + * empty or {@code null}, the value of {@code defaultStr}.

              + * + *
              +     * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
              +     * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
              +     * StringUtils.defaultIfEmpty(" ", "NULL")   = " "
              +     * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
              +     * StringUtils.defaultIfEmpty("", null)      = null
              +     * 
              + * @param the specific kind of CharSequence + * @param str the CharSequence to check, may be null + * @param defaultStr the default CharSequence to return + * if the input is empty ("") or {@code null}, may be null + * @return the passed in CharSequence, or the default + * @see StringUtils#defaultString(String, String) + */ + public static T defaultIfEmpty(final T str, final T defaultStr) { + return isEmpty(str) ? defaultStr : str; + } + + // Rotating (circular shift) + //----------------------------------------------------------------------- + /** + *

              Rotate (circular shift) a String of {@code shift} characters.

              + *
                + *
              • If {@code shift > 0}, right circular shift (ex : ABCDEF => FABCDE)
              • + *
              • If {@code shift < 0}, left circular shift (ex : ABCDEF => BCDEFA)
              • + *
              + * + *
              +     * StringUtils.rotate(null, *)        = null
              +     * StringUtils.rotate("", *)          = ""
              +     * StringUtils.rotate("abcdefg", 0)   = "abcdefg"
              +     * StringUtils.rotate("abcdefg", 2)   = "fgabcde"
              +     * StringUtils.rotate("abcdefg", -2)  = "cdefgab"
              +     * StringUtils.rotate("abcdefg", 7)   = "abcdefg"
              +     * StringUtils.rotate("abcdefg", -7)  = "abcdefg"
              +     * StringUtils.rotate("abcdefg", 9)   = "fgabcde"
              +     * StringUtils.rotate("abcdefg", -9)  = "cdefgab"
              +     * 
              + * + * @param str the String to rotate, may be null + * @param shift number of time to shift (positive : right shift, negative : left shift) + * @return the rotated String, + * or the original String if {@code shift == 0}, + * or {@code null} if null String input + * @since 3.5 + */ + public static String rotate(final String str, final int shift) { + if (str == null) { + return null; + } + + final int strLen = str.length(); + if (shift == 0 || strLen == 0 || shift % strLen == 0) { + return str; + } + + final StringBuilder builder = new StringBuilder(strLen); + final int offset = - (shift % strLen); + builder.append(substring(str, offset)); + builder.append(substring(str, 0, offset)); + return builder.toString(); + } + + // Reversing + //----------------------------------------------------------------------- + /** + *

              Reverses a String as per {@link StringBuilder#reverse()}.

              + * + *

              A {@code null} String returns {@code null}.

              + * + *
              +     * StringUtils.reverse(null)  = null
              +     * StringUtils.reverse("")    = ""
              +     * StringUtils.reverse("bat") = "tab"
              +     * 
              + * + * @param str the String to reverse, may be null + * @return the reversed String, {@code null} if null String input + */ + public static String reverse(final String str) { + if (str == null) { + return null; + } + return new StringBuilder(str).reverse().toString(); + } + + /** + *

              Reverses a String that is delimited by a specific character.

              + * + *

              The Strings between the delimiters are not reversed. + * Thus java.lang.String becomes String.lang.java (if the delimiter + * is {@code '.'}).

              + * + *
              +     * StringUtils.reverseDelimited(null, *)      = null
              +     * StringUtils.reverseDelimited("", *)        = ""
              +     * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
              +     * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
              +     * 
              + * + * @param str the String to reverse, may be null + * @param separatorChar the separator character to use + * @return the reversed String, {@code null} if null String input + * @since 2.0 + */ + public static String reverseDelimited(final String str, final char separatorChar) { + if (str == null) { + return null; + } + // could implement manually, but simple way is to reuse other, + // probably slower, methods. + final String[] strs = split(str, separatorChar); + ArrayUtils.reverse(strs); + return join(strs, separatorChar); + } + + // Abbreviating + //----------------------------------------------------------------------- + /** + *

              Abbreviates a String using ellipses. This will turn + * "Now is the time for all good men" into "Now is the time for..."

              + * + *

              Specifically:

              + *
                + *
              • If the number of characters in {@code str} is less than or equal to + * {@code maxWidth}, return {@code str}.
              • + *
              • Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.
              • + *
              • If {@code maxWidth} is less than {@code 4}, throw an + * {@code IllegalArgumentException}.
              • + *
              • In no case will it return a String of length greater than + * {@code maxWidth}.
              • + *
              + * + *
              +     * StringUtils.abbreviate(null, *)      = null
              +     * StringUtils.abbreviate("", 4)        = ""
              +     * StringUtils.abbreviate("abcdefg", 6) = "abc..."
              +     * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
              +     * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
              +     * StringUtils.abbreviate("abcdefg", 4) = "a..."
              +     * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
              +     * 
              + * + * @param str the String to check, may be null + * @param maxWidth maximum length of result String, must be at least 4 + * @return abbreviated String, {@code null} if null String input + * @throws IllegalArgumentException if the width is too small + * @since 2.0 + */ + public static String abbreviate(final String str, final int maxWidth) { + final String defaultAbbrevMarker = "..."; + return abbreviate(str, defaultAbbrevMarker, 0, maxWidth); + } + + /** + *

              Abbreviates a String using ellipses. This will turn + * "Now is the time for all good men" into "...is the time for..."

              + * + *

              Works like {@code abbreviate(String, int)}, but allows you to specify + * a "left edge" offset. Note that this left edge is not necessarily going to + * be the leftmost character in the result, or the first character following the + * ellipses, but it will appear somewhere in the result. + * + *

              In no case will it return a String of length greater than + * {@code maxWidth}.

              + * + *
              +     * StringUtils.abbreviate(null, *, *)                = null
              +     * StringUtils.abbreviate("", 0, 4)                  = ""
              +     * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
              +     * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
              +     * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
              +     * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
              +     * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
              +     * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
              +     * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
              +     * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
              +     * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
              +     * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
              +     * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
              +     * 
              + * + * @param str the String to check, may be null + * @param offset left edge of source String + * @param maxWidth maximum length of result String, must be at least 4 + * @return abbreviated String, {@code null} if null String input + * @throws IllegalArgumentException if the width is too small + * @since 2.0 + */ + public static String abbreviate(final String str, final int offset, final int maxWidth) { + final String defaultAbbrevMarker = "..."; + return abbreviate(str, defaultAbbrevMarker, offset, maxWidth); + } + + /** + *

              Abbreviates a String using another given String as replacement marker. This will turn + * "Now is the time for all good men" into "Now is the time for..." if "..." was defined + * as the replacement marker.

              + * + *

              Specifically:

              + *
                + *
              • If the number of characters in {@code str} is less than or equal to + * {@code maxWidth}, return {@code str}.
              • + *
              • Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.
              • + *
              • If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an + * {@code IllegalArgumentException}.
              • + *
              • In no case will it return a String of length greater than + * {@code maxWidth}.
              • + *
              + * + *
              +     * StringUtils.abbreviate(null, "...", *)      = null
              +     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
              +     * StringUtils.abbreviate("", "...", 4)        = ""
              +     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
              +     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
              +     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
              +     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
              +     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
              +     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
              +     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
              +     * 
              + * + * @param str the String to check, may be null + * @param abbrevMarker the String used as replacement marker + * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1} + * @return abbreviated String, {@code null} if null String input + * @throws IllegalArgumentException if the width is too small + * @since 3.6 + */ + public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { + return abbreviate(str, abbrevMarker, 0, maxWidth); + } + + /** + *

              Abbreviates a String using a given replacement marker. This will turn + * "Now is the time for all good men" into "...is the time for..." if "..." was defined + * as the replacement marker.

              + * + *

              Works like {@code abbreviate(String, String, int)}, but allows you to specify + * a "left edge" offset. Note that this left edge is not necessarily going to + * be the leftmost character in the result, or the first character following the + * replacement marker, but it will appear somewhere in the result. + * + *

              In no case will it return a String of length greater than {@code maxWidth}.

              + * + *
              +     * StringUtils.abbreviate(null, null, *, *)                 = null
              +     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
              +     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
              +     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
              +     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
              +     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
              +     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
              +     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
              +     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
              +     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
              +     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
              +     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
              +     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
              +     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
              +     * 
              + * + * @param str the String to check, may be null + * @param abbrevMarker the String used as replacement marker + * @param offset left edge of source String + * @param maxWidth maximum length of result String, must be at least 4 + * @return abbreviated String, {@code null} if null String input + * @throws IllegalArgumentException if the width is too small + * @since 3.6 + */ + public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { + if (isEmpty(str) || isEmpty(abbrevMarker)) { + return str; + } + + final int abbrevMarkerLength = abbrevMarker.length(); + final int minAbbrevWidth = abbrevMarkerLength + 1; + final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1; + + if (maxWidth < minAbbrevWidth) { + throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth)); + } + if (str.length() <= maxWidth) { + return str; + } + if (offset > str.length()) { + offset = str.length(); + } + if (str.length() - offset < maxWidth - abbrevMarkerLength) { + offset = str.length() - (maxWidth - abbrevMarkerLength); + } + if (offset <= abbrevMarkerLength+1) { + return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker; + } + if (maxWidth < minAbbrevWidthOffset) { + throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset)); + } + if (offset + maxWidth - abbrevMarkerLength < str.length()) { + return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength); + } + return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength)); + } + + /** + *

              Abbreviates a String to the length passed, replacing the middle characters with the supplied + * replacement String.

              + * + *

              This abbreviation only occurs if the following criteria is met:

              + *
                + *
              • Neither the String for abbreviation nor the replacement String are null or empty
              • + *
              • The length to truncate to is less than the length of the supplied String
              • + *
              • The length to truncate to is greater than 0
              • + *
              • The abbreviated String will have enough room for the length supplied replacement String + * and the first and last characters of the supplied String for abbreviation
              • + *
              + *

              Otherwise, the returned String will be the same as the supplied String for abbreviation. + *

              + * + *
              +     * StringUtils.abbreviateMiddle(null, null, 0)      = null
              +     * StringUtils.abbreviateMiddle("abc", null, 0)      = "abc"
              +     * StringUtils.abbreviateMiddle("abc", ".", 0)      = "abc"
              +     * StringUtils.abbreviateMiddle("abc", ".", 3)      = "abc"
              +     * StringUtils.abbreviateMiddle("abcdef", ".", 4)     = "ab.f"
              +     * 
              + * + * @param str the String to abbreviate, may be null + * @param middle the String to replace the middle characters with, may be null + * @param length the length to abbreviate {@code str} to. + * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation. + * @since 2.5 + */ + public static String abbreviateMiddle(final String str, final String middle, final int length) { + if (isEmpty(str) || isEmpty(middle)) { + return str; + } + + if (length >= str.length() || length < middle.length()+2) { + return str; + } + + final int targetSting = length-middle.length(); + final int startOffset = targetSting/2+targetSting%2; + final int endOffset = str.length()-targetSting/2; + + final StringBuilder builder = new StringBuilder(length); + builder.append(str.substring(0,startOffset)); + builder.append(middle); + builder.append(str.substring(endOffset)); + + return builder.toString(); + } + + // Difference + //----------------------------------------------------------------------- + /** + *

              Compares two Strings, and returns the portion where they differ. + * More precisely, return the remainder of the second String, + * starting from where it's different from the first. This means that + * the difference between "abc" and "ab" is the empty String and not "c".

              + * + *

              For example, + * {@code difference("i am a machine", "i am a robot") -> "robot"}.

              + * + *
              +     * StringUtils.difference(null, null) = null
              +     * StringUtils.difference("", "") = ""
              +     * StringUtils.difference("", "abc") = "abc"
              +     * StringUtils.difference("abc", "") = ""
              +     * StringUtils.difference("abc", "abc") = ""
              +     * StringUtils.difference("abc", "ab") = ""
              +     * StringUtils.difference("ab", "abxyz") = "xyz"
              +     * StringUtils.difference("abcde", "abxyz") = "xyz"
              +     * StringUtils.difference("abcde", "xyz") = "xyz"
              +     * 
              + * + * @param str1 the first String, may be null + * @param str2 the second String, may be null + * @return the portion of str2 where it differs from str1; returns the + * empty String if they are equal + * @see #indexOfDifference(CharSequence,CharSequence) + * @since 2.0 + */ + public static String difference(final String str1, final String str2) { + if (str1 == null) { + return str2; + } + if (str2 == null) { + return str1; + } + final int at = indexOfDifference(str1, str2); + if (at == INDEX_NOT_FOUND) { + return EMPTY; + } + return str2.substring(at); + } + + /** + *

              Compares two CharSequences, and returns the index at which the + * CharSequences begin to differ.

              + * + *

              For example, + * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}

              + * + *
              +     * StringUtils.indexOfDifference(null, null) = -1
              +     * StringUtils.indexOfDifference("", "") = -1
              +     * StringUtils.indexOfDifference("", "abc") = 0
              +     * StringUtils.indexOfDifference("abc", "") = 0
              +     * StringUtils.indexOfDifference("abc", "abc") = -1
              +     * StringUtils.indexOfDifference("ab", "abxyz") = 2
              +     * StringUtils.indexOfDifference("abcde", "abxyz") = 2
              +     * StringUtils.indexOfDifference("abcde", "xyz") = 0
              +     * 
              + * + * @param cs1 the first CharSequence, may be null + * @param cs2 the second CharSequence, may be null + * @return the index where cs1 and cs2 begin to differ; -1 if they are equal + * @since 2.0 + * @since 3.0 Changed signature from indexOfDifference(String, String) to + * indexOfDifference(CharSequence, CharSequence) + */ + public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { + if (cs1 == cs2) { + return INDEX_NOT_FOUND; + } + if (cs1 == null || cs2 == null) { + return 0; + } + int i; + for (i = 0; i < cs1.length() && i < cs2.length(); ++i) { + if (cs1.charAt(i) != cs2.charAt(i)) { + break; + } + } + if (i < cs2.length() || i < cs1.length()) { + return i; + } + return INDEX_NOT_FOUND; + } + + /** + *

              Compares all CharSequences in an array and returns the index at which the + * CharSequences begin to differ.

              + * + *

              For example, + * indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -> 7

              + * + *
              +     * StringUtils.indexOfDifference(null) = -1
              +     * StringUtils.indexOfDifference(new String[] {}) = -1
              +     * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
              +     * StringUtils.indexOfDifference(new String[] {null, null}) = -1
              +     * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
              +     * StringUtils.indexOfDifference(new String[] {"", null}) = 0
              +     * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
              +     * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
              +     * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
              +     * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
              +     * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
              +     * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
              +     * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
              +     * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
              +     * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
              +     * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
              +     * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
              +     * 
              + * + * @param css array of CharSequences, entries may be null + * @return the index where the strings begin to differ; -1 if they are all equal + * @since 2.4 + * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...) + */ + public static int indexOfDifference(final CharSequence... css) { + if (css == null || css.length <= 1) { + return INDEX_NOT_FOUND; + } + boolean anyStringNull = false; + boolean allStringsNull = true; + final int arrayLen = css.length; + int shortestStrLen = Integer.MAX_VALUE; + int longestStrLen = 0; + + // find the min and max string lengths; this avoids checking to make + // sure we are not exceeding the length of the string each time through + // the bottom loop. + for (CharSequence cs : css) { + if (cs == null) { + anyStringNull = true; + shortestStrLen = 0; + } else { + allStringsNull = false; + shortestStrLen = Math.min(cs.length(), shortestStrLen); + longestStrLen = Math.max(cs.length(), longestStrLen); + } + } + + // handle lists containing all nulls or all empty strings + if (allStringsNull || longestStrLen == 0 && !anyStringNull) { + return INDEX_NOT_FOUND; + } + + // handle lists containing some nulls or some empty strings + if (shortestStrLen == 0) { + return 0; + } + + // find the position with the first difference across all strings + int firstDiff = -1; + for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) { + final char comparisonChar = css[0].charAt(stringPos); + for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) { + if (css[arrayPos].charAt(stringPos) != comparisonChar) { + firstDiff = stringPos; + break; + } + } + if (firstDiff != -1) { + break; + } + } + + if (firstDiff == -1 && shortestStrLen != longestStrLen) { + // we compared all of the characters up to the length of the + // shortest string and didn't find a match, but the string lengths + // vary, so return the length of the shortest string. + return shortestStrLen; + } + return firstDiff; + } + + /** + *

              Compares all Strings in an array and returns the initial sequence of + * characters that is common to all of them.

              + * + *

              For example, + * getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -> "i am a "

              + * + *
              +     * StringUtils.getCommonPrefix(null) = ""
              +     * StringUtils.getCommonPrefix(new String[] {}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
              +     * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
              +     * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
              +     * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
              +     * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
              +     * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
              +     * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
              +     * 
              + * + * @param strs array of String objects, entries may be null + * @return the initial sequence of characters that are common to all Strings + * in the array; empty String if the array is null, the elements are all null + * or if there is no common prefix. + * @since 2.4 + */ + public static String getCommonPrefix(final String... strs) { + if (strs == null || strs.length == 0) { + return EMPTY; + } + final int smallestIndexOfDiff = indexOfDifference(strs); + if (smallestIndexOfDiff == INDEX_NOT_FOUND) { + // all strings were identical + if (strs[0] == null) { + return EMPTY; + } + return strs[0]; + } else if (smallestIndexOfDiff == 0) { + // there were no common initial characters + return EMPTY; + } else { + // we found a common initial character sequence + return strs[0].substring(0, smallestIndexOfDiff); + } + } + + // Misc + //----------------------------------------------------------------------- + /** + *

              Find the Levenshtein distance between two Strings.

              + * + *

              This is the number of changes needed to change one String into + * another, where each change is a single character modification (deletion, + * insertion or substitution).

              + * + *

              The implementation uses a single-dimensional array of length s.length() + 1. See + * + * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html for details.

              + * + *
              +     * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
              +     * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
              +     * StringUtils.getLevenshteinDistance("","")               = 0
              +     * StringUtils.getLevenshteinDistance("","a")              = 1
              +     * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
              +     * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
              +     * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
              +     * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
              +     * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
              +     * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
              +     * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
              +     * 
              + * + * @param s the first String, must not be null + * @param t the second String, must not be null + * @return result distance + * @throws IllegalArgumentException if either String input {@code null} + * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to + * getLevenshteinDistance(CharSequence, CharSequence) + * @deprecated as of 3.6, use commons-text + * + * LevenshteinDistance instead + */ + @Deprecated + public static int getLevenshteinDistance(CharSequence s, CharSequence t) { + if (s == null || t == null) { + throw new IllegalArgumentException("Strings must not be null"); + } + + int n = s.length(); + int m = t.length(); + + if (n == 0) { + return m; + } else if (m == 0) { + return n; + } + + if (n > m) { + // swap the input strings to consume less memory + final CharSequence tmp = s; + s = t; + t = tmp; + n = m; + m = t.length(); + } + + final int p[] = new int[n + 1]; + // indexes into strings s and t + int i; // iterates through s + int j; // iterates through t + int upper_left; + int upper; + + char t_j; // jth character of t + int cost; + + for (i = 0; i <= n; i++) { + p[i] = i; + } + + for (j = 1; j <= m; j++) { + upper_left = p[0]; + t_j = t.charAt(j - 1); + p[0] = j; + + for (i = 1; i <= n; i++) { + upper = p[i]; + cost = s.charAt(i - 1) == t_j ? 0 : 1; + // minimum of cell to the left+1, to the top+1, diagonally left and up +cost + p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost); + upper_left = upper; + } + } + + return p[n]; + } + + /** + *

              Find the Levenshtein distance between two Strings if it's less than or equal to a given + * threshold.

              + * + *

              This is the number of changes needed to change one String into + * another, where each change is a single character modification (deletion, + * insertion or substitution).

              + * + *

              This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield + * and Chas Emerick's implementation of the Levenshtein distance algorithm from + * http://www.merriampark.com/ld.htm

              + * + *
              +     * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
              +     * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
              +     * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
              +     * StringUtils.getLevenshteinDistance("","", 0)               = 0
              +     * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
              +     * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
              +     * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
              +     * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
              +     * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
              +     * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
              +     * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
              +     * 
              + * + * @param s the first String, must not be null + * @param t the second String, must not be null + * @param threshold the target threshold, must not be negative + * @return result distance, or {@code -1} if the distance would be greater than the threshold + * @throws IllegalArgumentException if either String input {@code null} or negative threshold + * @deprecated as of 3.6, use commons-text + * + * LevenshteinDistance instead + */ + @Deprecated + public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { + if (s == null || t == null) { + throw new IllegalArgumentException("Strings must not be null"); + } + if (threshold < 0) { + throw new IllegalArgumentException("Threshold must not be negative"); + } + + /* + This implementation only computes the distance if it's less than or equal to the + threshold value, returning -1 if it's greater. The advantage is performance: unbounded + distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only + computing a diagonal stripe of width 2k + 1 of the cost table. + It is also possible to use this to compute the unbounded Levenshtein distance by starting + the threshold at 1 and doubling each time until the distance is found; this is O(dm), where + d is the distance. + + One subtlety comes from needing to ignore entries on the border of our stripe + eg. + p[] = |#|#|#|* + d[] = *|#|#|#| + We must ignore the entry to the left of the leftmost member + We must ignore the entry above the rightmost member + + Another subtlety comes from our stripe running off the matrix if the strings aren't + of the same size. Since string s is always swapped to be the shorter of the two, + the stripe will always run off to the upper right instead of the lower left of the matrix. + + As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1. + In this case we're going to walk a stripe of length 3. The matrix would look like so: + + 1 2 3 4 5 + 1 |#|#| | | | + 2 |#|#|#| | | + 3 | |#|#|#| | + 4 | | |#|#|#| + 5 | | | |#|#| + 6 | | | | |#| + 7 | | | | | | + + Note how the stripe leads off the table as there is no possible way to turn a string of length 5 + into one of length 7 in edit distance of 1. + + Additionally, this implementation decreases memory usage by using two + single-dimensional arrays and swapping them back and forth instead of allocating + an entire n by m matrix. This requires a few minor changes, such as immediately returning + when it's detected that the stripe has run off the matrix and initially filling the arrays with + large values so that entries we don't compute are ignored. + + See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion. + */ + + int n = s.length(); // length of s + int m = t.length(); // length of t + + // if one string is empty, the edit distance is necessarily the length of the other + if (n == 0) { + return m <= threshold ? m : -1; + } else if (m == 0) { + return n <= threshold ? n : -1; + } + // no need to calculate the distance if the length difference is greater than the threshold + else if (Math.abs(n - m) > threshold) { + return -1; + } + + if (n > m) { + // swap the two strings to consume less memory + final CharSequence tmp = s; + s = t; + t = tmp; + n = m; + m = t.length(); + } + + int p[] = new int[n + 1]; // 'previous' cost array, horizontally + int d[] = new int[n + 1]; // cost array, horizontally + int _d[]; // placeholder to assist in swapping p and d + + // fill in starting table values + final int boundary = Math.min(n, threshold) + 1; + for (int i = 0; i < boundary; i++) { + p[i] = i; + } + // these fills ensure that the value above the rightmost entry of our + // stripe will be ignored in following loop iterations + Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE); + Arrays.fill(d, Integer.MAX_VALUE); + + // iterates through t + for (int j = 1; j <= m; j++) { + final char t_j = t.charAt(j - 1); // jth character of t + d[0] = j; + + // compute stripe indices, constrain to array size + final int min = Math.max(1, j - threshold); + final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold); + + // the stripe may lead off of the table if s and t are of different sizes + if (min > max) { + return -1; + } + + // ignore entry left of leftmost + if (min > 1) { + d[min - 1] = Integer.MAX_VALUE; + } + + // iterates through [min, max] in s + for (int i = min; i <= max; i++) { + if (s.charAt(i - 1) == t_j) { + // diagonally left and up + d[i] = p[i - 1]; + } else { + // 1 + minimum of cell to the left, to the top, diagonally left and up + d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]); + } + } + + // copy current distance counts to 'previous row' distance counts + _d = p; + p = d; + d = _d; + } + + // if p[n] is greater than the threshold, there's no guarantee on it being the correct + // distance + if (p[n] <= threshold) { + return p[n]; + } + return -1; + } + + /** + *

              Find the Jaro Winkler Distance which indicates the similarity score between two Strings.

              + * + *

              The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters. + * Winkler increased this measure for matching initial characters.

              + * + *

              This implementation is based on the Jaro Winkler similarity algorithm + * from http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance.

              + * + *
              +     * StringUtils.getJaroWinklerDistance(null, null)          = IllegalArgumentException
              +     * StringUtils.getJaroWinklerDistance("","")               = 0.0
              +     * StringUtils.getJaroWinklerDistance("","a")              = 0.0
              +     * StringUtils.getJaroWinklerDistance("aaapppp", "")       = 0.0
              +     * StringUtils.getJaroWinklerDistance("frog", "fog")       = 0.93
              +     * StringUtils.getJaroWinklerDistance("fly", "ant")        = 0.0
              +     * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
              +     * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
              +     * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
              +     * StringUtils.getJaroWinklerDistance("hello", "hallo")    = 0.88
              +     * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
              +     * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D & H Enterprises, Inc.") = 0.95
              +     * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
              +     * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
              +     * 
              + * + * @param first the first String, must not be null + * @param second the second String, must not be null + * @return result distance + * @throws IllegalArgumentException if either String input {@code null} + * @since 3.3 + * @deprecated as of 3.6, use commons-text + * + * JaroWinklerDistance instead + */ + @Deprecated + public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { + final double DEFAULT_SCALING_FACTOR = 0.1; + + if (first == null || second == null) { + throw new IllegalArgumentException("Strings must not be null"); + } + + final int[] mtp = matches(first, second); + final double m = mtp[0]; + if (m == 0) { + return 0D; + } + final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3; + final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j); + return Math.round(jw * 100.0D) / 100.0D; + } + + private static int[] matches(final CharSequence first, final CharSequence second) { + CharSequence max, min; + if (first.length() > second.length()) { + max = first; + min = second; + } else { + max = second; + min = first; + } + final int range = Math.max(max.length() / 2 - 1, 0); + final int[] matchIndexes = new int[min.length()]; + Arrays.fill(matchIndexes, -1); + final boolean[] matchFlags = new boolean[max.length()]; + int matches = 0; + for (int mi = 0; mi < min.length(); mi++) { + final char c1 = min.charAt(mi); + for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) { + if (!matchFlags[xi] && c1 == max.charAt(xi)) { + matchIndexes[mi] = xi; + matchFlags[xi] = true; + matches++; + break; + } + } + } + final char[] ms1 = new char[matches]; + final char[] ms2 = new char[matches]; + for (int i = 0, si = 0; i < min.length(); i++) { + if (matchIndexes[i] != -1) { + ms1[si] = min.charAt(i); + si++; + } + } + for (int i = 0, si = 0; i < max.length(); i++) { + if (matchFlags[i]) { + ms2[si] = max.charAt(i); + si++; + } + } + int transpositions = 0; + for (int mi = 0; mi < ms1.length; mi++) { + if (ms1[mi] != ms2[mi]) { + transpositions++; + } + } + int prefix = 0; + for (int mi = 0; mi < min.length(); mi++) { + if (first.charAt(mi) == second.charAt(mi)) { + prefix++; + } else { + break; + } + } + return new int[] { matches, transpositions / 2, prefix, max.length() }; + } + + /** + *

              Find the Fuzzy Distance which indicates the similarity score between two Strings.

              + * + *

              This string matching algorithm is similar to the algorithms of editors such as Sublime Text, + * TextMate, Atom and others. One point is given for every matched character. Subsequent + * matches yield two bonus points. A higher score indicates a higher similarity.

              + * + *
              +     * StringUtils.getFuzzyDistance(null, null, null)                                    = IllegalArgumentException
              +     * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH)                              = 0
              +     * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH)                     = 0
              +     * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH)                         = 1
              +     * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH)                     = 1
              +     * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH)                    = 2
              +     * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH)                    = 4
              +     * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
              +     * 
              + * + * @param term a full term that should be matched against, must not be null + * @param query the query that will be matched against a term, must not be null + * @param locale This string matching logic is case insensitive. A locale is necessary to normalize + * both Strings to lower case. + * @return result score + * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null} + * @since 3.4 + * @deprecated as of 3.6, use commons-text + * + * FuzzyScore instead + */ + @Deprecated + public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { + if (term == null || query == null) { + throw new IllegalArgumentException("Strings must not be null"); + } else if (locale == null) { + throw new IllegalArgumentException("Locale must not be null"); + } + + // fuzzy logic is case insensitive. We normalize the Strings to lower + // case right from the start. Turning characters to lower case + // via Character.toLowerCase(char) is unfortunately insufficient + // as it does not accept a locale. + final String termLowerCase = term.toString().toLowerCase(locale); + final String queryLowerCase = query.toString().toLowerCase(locale); + + // the resulting score + int score = 0; + + // the position in the term which will be scanned next for potential + // query character matches + int termIndex = 0; + + // index of the previously matched character in the term + int previousMatchingCharacterIndex = Integer.MIN_VALUE; + + for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) { + final char queryChar = queryLowerCase.charAt(queryIndex); + + boolean termCharacterMatchFound = false; + for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) { + final char termChar = termLowerCase.charAt(termIndex); + + if (queryChar == termChar) { + // simple character matches result in one point + score++; + + // subsequent character matches further improve + // the score. + if (previousMatchingCharacterIndex + 1 == termIndex) { + score += 2; + } + + previousMatchingCharacterIndex = termIndex; + + // we can leave the nested loop. Every character in the + // query can match at most one character in the term. + termCharacterMatchFound = true; + } + } + } + + return score; + } + + // startsWith + //----------------------------------------------------------------------- + + /** + *

              Check if a CharSequence starts with a specified prefix.

              + * + *

              {@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case sensitive.

              + * + *
              +     * StringUtils.startsWith(null, null)      = true
              +     * StringUtils.startsWith(null, "abc")     = false
              +     * StringUtils.startsWith("abcdef", null)  = false
              +     * StringUtils.startsWith("abcdef", "abc") = true
              +     * StringUtils.startsWith("ABCDEF", "abc") = false
              +     * 
              + * + * @see java.lang.String#startsWith(String) + * @param str the CharSequence to check, may be null + * @param prefix the prefix to find, may be null + * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or + * both {@code null} + * @since 2.4 + * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence) + */ + public static boolean startsWith(final CharSequence str, final CharSequence prefix) { + return startsWith(str, prefix, false); + } + + /** + *

              Case insensitive check if a CharSequence starts with a specified prefix.

              + * + *

              {@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case insensitive.

              + * + *
              +     * StringUtils.startsWithIgnoreCase(null, null)      = true
              +     * StringUtils.startsWithIgnoreCase(null, "abc")     = false
              +     * StringUtils.startsWithIgnoreCase("abcdef", null)  = false
              +     * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
              +     * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
              +     * 
              + * + * @see java.lang.String#startsWith(String) + * @param str the CharSequence to check, may be null + * @param prefix the prefix to find, may be null + * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or + * both {@code null} + * @since 2.4 + * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence) + */ + public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { + return startsWith(str, prefix, true); + } + + /** + *

              Check if a CharSequence starts with a specified prefix (optionally case insensitive).

              + * + * @see java.lang.String#startsWith(String) + * @param str the CharSequence to check, may be null + * @param prefix the prefix to find, may be null + * @param ignoreCase indicates whether the compare should ignore case + * (case insensitive) or not. + * @return {@code true} if the CharSequence starts with the prefix or + * both {@code null} + */ + private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) { + if (str == null || prefix == null) { + return str == null && prefix == null; + } + if (prefix.length() > str.length()) { + return false; + } + return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length()); + } + + /** + *

              Check if a CharSequence starts with any of the provided case-sensitive prefixes.

              + * + *
              +     * StringUtils.startsWithAny(null, null)      = false
              +     * StringUtils.startsWithAny(null, new String[] {"abc"})  = false
              +     * StringUtils.startsWithAny("abcxyz", null)     = false
              +     * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
              +     * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
              +     * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
              +     * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
              +     * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
              +     * 
              + * + * @param sequence the CharSequence to check, may be null + * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null} + * @see StringUtils#startsWith(CharSequence, CharSequence) + * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or + * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}. + * @since 2.5 + * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...) + */ + public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { + if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { + return false; + } + for (final CharSequence searchString : searchStrings) { + if (startsWith(sequence, searchString)) { + return true; + } + } + return false; + } + + // endsWith + //----------------------------------------------------------------------- + + /** + *

              Check if a CharSequence ends with a specified suffix.

              + * + *

              {@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case sensitive.

              + * + *
              +     * StringUtils.endsWith(null, null)      = true
              +     * StringUtils.endsWith(null, "def")     = false
              +     * StringUtils.endsWith("abcdef", null)  = false
              +     * StringUtils.endsWith("abcdef", "def") = true
              +     * StringUtils.endsWith("ABCDEF", "def") = false
              +     * StringUtils.endsWith("ABCDEF", "cde") = false
              +     * StringUtils.endsWith("ABCDEF", "")    = true
              +     * 
              + * + * @see java.lang.String#endsWith(String) + * @param str the CharSequence to check, may be null + * @param suffix the suffix to find, may be null + * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or + * both {@code null} + * @since 2.4 + * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence) + */ + public static boolean endsWith(final CharSequence str, final CharSequence suffix) { + return endsWith(str, suffix, false); + } + + /** + *

              Case insensitive check if a CharSequence ends with a specified suffix.

              + * + *

              {@code null}s are handled without exceptions. Two {@code null} + * references are considered to be equal. The comparison is case insensitive.

              + * + *
              +     * StringUtils.endsWithIgnoreCase(null, null)      = true
              +     * StringUtils.endsWithIgnoreCase(null, "def")     = false
              +     * StringUtils.endsWithIgnoreCase("abcdef", null)  = false
              +     * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
              +     * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
              +     * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
              +     * 
              + * + * @see java.lang.String#endsWith(String) + * @param str the CharSequence to check, may be null + * @param suffix the suffix to find, may be null + * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or + * both {@code null} + * @since 2.4 + * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence) + */ + public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { + return endsWith(str, suffix, true); + } + + /** + *

              Check if a CharSequence ends with a specified suffix (optionally case insensitive).

              + * + * @see java.lang.String#endsWith(String) + * @param str the CharSequence to check, may be null + * @param suffix the suffix to find, may be null + * @param ignoreCase indicates whether the compare should ignore case + * (case insensitive) or not. + * @return {@code true} if the CharSequence starts with the prefix or + * both {@code null} + */ + private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { + if (str == null || suffix == null) { + return str == null && suffix == null; + } + if (suffix.length() > str.length()) { + return false; + } + final int strOffset = str.length() - suffix.length(); + return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); + } + + /** + *

              + * Similar to http://www.w3.org/TR/xpath/#function-normalize + * -space + *

              + *

              + * The function returns the argument string with whitespace normalized by using + * {@link #trim(String)} to remove leading and trailing whitespace + * and then replacing sequences of whitespace characters by a single space. + *

              + * In XML Whitespace characters are the same as those allowed by the S production, which is S ::= (#x20 | #x9 | #xD | #xA)+ + *

              + * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r] + * + *

              For reference:

              + *
                + *
              • \x0B = vertical tab
              • + *
              • \f = #xC = form feed
              • + *
              • #x20 = space
              • + *
              • #x9 = \t
              • + *
              • #xA = \n
              • + *
              • #xD = \r
              • + *
              + * + *

              + * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also + * normalize. Additionally {@link #trim(String)} removes control characters (char <= 32) from both + * ends of this String. + *

              + * + * @see Pattern + * @see #trim(String) + * @see http://www.w3.org/TR/xpath/#function-normalize-space + * @param str the source String to normalize whitespaces from, may be null + * @return the modified string with whitespace normalized, {@code null} if null String input + * + * @since 3.0 + */ + public static String normalizeSpace(final String str) { + // LANG-1020: Improved performance significantly by normalizing manually instead of using regex + // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test + if (isEmpty(str)) { + return str; + } + final int size = str.length(); + final char[] newChars = new char[size]; + int count = 0; + int whitespacesCount = 0; + boolean startWhitespaces = true; + for (int i = 0; i < size; i++) { + final char actualChar = str.charAt(i); + final boolean isWhitespace = Character.isWhitespace(actualChar); + if (!isWhitespace) { + startWhitespaces = false; + newChars[count++] = (actualChar == 160 ? 32 : actualChar); + whitespacesCount = 0; + } else { + if (whitespacesCount == 0 && !startWhitespaces) { + newChars[count++] = SPACE.charAt(0); + } + whitespacesCount++; + } + } + if (startWhitespaces) { + return EMPTY; + } + return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim(); + } + + /** + *

              Check if a CharSequence ends with any of the provided case-sensitive suffixes.

              + * + *
              +     * StringUtils.endsWithAny(null, null)      = false
              +     * StringUtils.endsWithAny(null, new String[] {"abc"})  = false
              +     * StringUtils.endsWithAny("abcxyz", null)     = false
              +     * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
              +     * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
              +     * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
              +     * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
              +     * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
              +     * 
              + * + * @param sequence the CharSequence to check, may be null + * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null} + * @see StringUtils#endsWith(CharSequence, CharSequence) + * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or + * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}. + * @since 3.0 + */ + public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { + if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) { + return false; + } + for (final CharSequence searchString : searchStrings) { + if (endsWith(sequence, searchString)) { + return true; + } + } + return false; + } + + /** + * Appends the suffix to the end of the string if the string does not + * already end with the suffix. + * + * @param str The string. + * @param suffix The suffix to append to the end of the string. + * @param ignoreCase Indicates whether the compare should ignore case. + * @param suffixes Additional suffixes that are valid terminators (optional). + * + * @return A new String if suffix was appended, the same string otherwise. + */ + private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) { + if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) { + return str; + } + if (suffixes != null && suffixes.length > 0) { + for (final CharSequence s : suffixes) { + if (endsWith(str, s, ignoreCase)) { + return str; + } + } + } + return str + suffix.toString(); + } + + /** + * Appends the suffix to the end of the string if the string does not + * already end with any of the suffixes. + * + *
              +     * StringUtils.appendIfMissing(null, null) = null
              +     * StringUtils.appendIfMissing("abc", null) = "abc"
              +     * StringUtils.appendIfMissing("", "xyz") = "xyz"
              +     * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
              +     * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
              +     * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
              +     * 
              + *

              With additional suffixes,

              + *
              +     * StringUtils.appendIfMissing(null, null, null) = null
              +     * StringUtils.appendIfMissing("abc", null, null) = "abc"
              +     * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
              +     * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
              +     * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
              +     * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
              +     * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
              +     * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
              +     * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
              +     * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
              +     * 
              + * + * @param str The string. + * @param suffix The suffix to append to the end of the string. + * @param suffixes Additional suffixes that are valid terminators. + * + * @return A new String if suffix was appended, the same string otherwise. + * + * @since 3.2 + */ + public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { + return appendIfMissing(str, suffix, false, suffixes); + } + + /** + * Appends the suffix to the end of the string if the string does not + * already end, case insensitive, with any of the suffixes. + * + *
              +     * StringUtils.appendIfMissingIgnoreCase(null, null) = null
              +     * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
              +     * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
              +     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
              +     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
              +     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
              +     * 
              + *

              With additional suffixes,

              + *
              +     * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
              +     * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
              +     * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
              +     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
              +     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
              +     * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
              +     * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
              +     * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
              +     * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
              +     * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
              +     * 
              + * + * @param str The string. + * @param suffix The suffix to append to the end of the string. + * @param suffixes Additional suffixes that are valid terminators. + * + * @return A new String if suffix was appended, the same string otherwise. + * + * @since 3.2 + */ + public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { + return appendIfMissing(str, suffix, true, suffixes); + } + + /** + * Prepends the prefix to the start of the string if the string does not + * already start with any of the prefixes. + * + * @param str The string. + * @param prefix The prefix to prepend to the start of the string. + * @param ignoreCase Indicates whether the compare should ignore case. + * @param prefixes Additional prefixes that are valid (optional). + * + * @return A new String if prefix was prepended, the same string otherwise. + */ + private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) { + if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) { + return str; + } + if (prefixes != null && prefixes.length > 0) { + for (final CharSequence p : prefixes) { + if (startsWith(str, p, ignoreCase)) { + return str; + } + } + } + return prefix.toString() + str; + } + + /** + * Prepends the prefix to the start of the string if the string does not + * already start with any of the prefixes. + * + *
              +     * StringUtils.prependIfMissing(null, null) = null
              +     * StringUtils.prependIfMissing("abc", null) = "abc"
              +     * StringUtils.prependIfMissing("", "xyz") = "xyz"
              +     * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
              +     * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
              +     * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
              +     * 
              + *

              With additional prefixes,

              + *
              +     * StringUtils.prependIfMissing(null, null, null) = null
              +     * StringUtils.prependIfMissing("abc", null, null) = "abc"
              +     * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
              +     * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
              +     * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
              +     * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
              +     * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
              +     * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
              +     * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
              +     * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
              +     * 
              + * + * @param str The string. + * @param prefix The prefix to prepend to the start of the string. + * @param prefixes Additional prefixes that are valid. + * + * @return A new String if prefix was prepended, the same string otherwise. + * + * @since 3.2 + */ + public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { + return prependIfMissing(str, prefix, false, prefixes); + } + + /** + * Prepends the prefix to the start of the string if the string does not + * already start, case insensitive, with any of the prefixes. + * + *
              +     * StringUtils.prependIfMissingIgnoreCase(null, null) = null
              +     * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
              +     * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
              +     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
              +     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
              +     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
              +     * 
              + *

              With additional prefixes,

              + *
              +     * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
              +     * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
              +     * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
              +     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
              +     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
              +     * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
              +     * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
              +     * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
              +     * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
              +     * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
              +     * 
              + * + * @param str The string. + * @param prefix The prefix to prepend to the start of the string. + * @param prefixes Additional prefixes that are valid (optional). + * + * @return A new String if prefix was prepended, the same string otherwise. + * + * @since 3.2 + */ + public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { + return prependIfMissing(str, prefix, true, prefixes); + } + + /** + * Converts a byte[] to a String using the specified character encoding. + * + * @param bytes + * the byte array to read from + * @param charsetName + * the encoding to use, if null then use the platform default + * @return a new String + * @throws UnsupportedEncodingException + * If the named charset is not supported + * @throws NullPointerException + * if the input is null + * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code + * @since 3.1 + */ + @Deprecated + public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { + return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset()); + } + + /** + * Converts a byte[] to a String using the specified character encoding. + * + * @param bytes + * the byte array to read from + * @param charset + * the encoding to use, if null then use the platform default + * @return a new String + * @throws NullPointerException + * if {@code bytes} is null + * @since 3.2 + * @since 3.3 No longer throws {@link UnsupportedEncodingException}. + */ + public static String toEncodedString(final byte[] bytes, final Charset charset) { + return new String(bytes, charset != null ? charset : Charset.defaultCharset()); + } + + /** + *

              + * Wraps a string with a char. + *

              + * + *
              +     * StringUtils.wrap(null, *)        = null
              +     * StringUtils.wrap("", *)          = ""
              +     * StringUtils.wrap("ab", '\0')     = "ab"
              +     * StringUtils.wrap("ab", 'x')      = "xabx"
              +     * StringUtils.wrap("ab", '\'')     = "'ab'"
              +     * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
              +     * 
              + * + * @param str + * the string to be wrapped, may be {@code null} + * @param wrapWith + * the char that will wrap {@code str} + * @return the wrapped string, or {@code null} if {@code str==null} + * @since 3.4 + */ + public static String wrap(final String str, final char wrapWith) { + + if (isEmpty(str) || wrapWith == '\0') { + return str; + } + + return wrapWith + str + wrapWith; + } + + /** + *

              + * Wraps a String with another String. + *

              + * + *

              + * A {@code null} input String returns {@code null}. + *

              + * + *
              +     * StringUtils.wrap(null, *)         = null
              +     * StringUtils.wrap("", *)           = ""
              +     * StringUtils.wrap("ab", null)      = "ab"
              +     * StringUtils.wrap("ab", "x")       = "xabx"
              +     * StringUtils.wrap("ab", "\"")      = "\"ab\""
              +     * StringUtils.wrap("\"ab\"", "\"")  = "\"\"ab\"\""
              +     * StringUtils.wrap("ab", "'")       = "'ab'"
              +     * StringUtils.wrap("'abcd'", "'")   = "''abcd''"
              +     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
              +     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
              +     * 
              + * + * @param str + * the String to be wrapper, may be null + * @param wrapWith + * the String that will wrap str + * @return wrapped String, {@code null} if null String input + * @since 3.4 + */ + public static String wrap(final String str, final String wrapWith) { + + if (isEmpty(str) || isEmpty(wrapWith)) { + return str; + } + + return wrapWith.concat(str).concat(wrapWith); + } + + /** + *

              + * Wraps a string with a char if that char is missing from the start or end of the given string. + *

              + * + *
              +     * StringUtils.wrap(null, *)        = null
              +     * StringUtils.wrap("", *)          = ""
              +     * StringUtils.wrap("ab", '\0')     = "ab"
              +     * StringUtils.wrap("ab", 'x')      = "xabx"
              +     * StringUtils.wrap("ab", '\'')     = "'ab'"
              +     * StringUtils.wrap("\"ab\"", '\"') = "\"ab\""
              +     * StringUtils.wrap("/", '/')  = "/"
              +     * StringUtils.wrap("a/b/c", '/')  = "/a/b/c/"
              +     * StringUtils.wrap("/a/b/c", '/')  = "/a/b/c/"
              +     * StringUtils.wrap("a/b/c/", '/')  = "/a/b/c/"
              +     * 
              + * + * @param str + * the string to be wrapped, may be {@code null} + * @param wrapWith + * the char that will wrap {@code str} + * @return the wrapped string, or {@code null} if {@code str==null} + * @since 3.5 + */ + public static String wrapIfMissing(final String str, final char wrapWith) { + if (isEmpty(str) || wrapWith == '\0') { + return str; + } + final StringBuilder builder = new StringBuilder(str.length() + 2); + if (str.charAt(0) != wrapWith) { + builder.append(wrapWith); + } + builder.append(str); + if (str.charAt(str.length() - 1) != wrapWith) { + builder.append(wrapWith); + } + return builder.toString(); + } + + /** + *

              + * Wraps a string with a string if that string is missing from the start or end of the given string. + *

              + * + *
              +     * StringUtils.wrap(null, *)         = null
              +     * StringUtils.wrap("", *)           = ""
              +     * StringUtils.wrap("ab", null)      = "ab"
              +     * StringUtils.wrap("ab", "x")       = "xabx"
              +     * StringUtils.wrap("ab", "\"")      = "\"ab\""
              +     * StringUtils.wrap("\"ab\"", "\"")  = "\"ab\""
              +     * StringUtils.wrap("ab", "'")       = "'ab'"
              +     * StringUtils.wrap("'abcd'", "'")   = "'abcd'"
              +     * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
              +     * StringUtils.wrap("'abcd'", "\"")  = "\"'abcd'\""
              +     * StringUtils.wrap("/", "/")  = "/"
              +     * StringUtils.wrap("a/b/c", "/")  = "/a/b/c/"
              +     * StringUtils.wrap("/a/b/c", "/")  = "/a/b/c/"
              +     * StringUtils.wrap("a/b/c/", "/")  = "/a/b/c/"
              +     * 
              + * + * @param str + * the string to be wrapped, may be {@code null} + * @param wrapWith + * the char that will wrap {@code str} + * @return the wrapped string, or {@code null} if {@code str==null} + * @since 3.5 + */ + public static String wrapIfMissing(final String str, final String wrapWith) { + if (isEmpty(str) || isEmpty(wrapWith)) { + return str; + } + final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length()); + if (!str.startsWith(wrapWith)) { + builder.append(wrapWith); + } + builder.append(str); + if (!str.endsWith(wrapWith)) { + builder.append(wrapWith); + } + return builder.toString(); + } + + /** + *

              + * Unwraps a given string from anther string. + *

              + * + *
              +     * StringUtils.unwrap(null, null)         = null
              +     * StringUtils.unwrap(null, "")           = null
              +     * StringUtils.unwrap(null, "1")          = null
              +     * StringUtils.unwrap("\'abc\'", "\'")    = "abc"
              +     * StringUtils.unwrap("\"abc\"", "\"")    = "abc"
              +     * StringUtils.unwrap("AABabcBAA", "AA")  = "BabcB"
              +     * StringUtils.unwrap("A", "#")           = "A"
              +     * StringUtils.unwrap("#A", "#")          = "#A"
              +     * StringUtils.unwrap("A#", "#")          = "A#"
              +     * 
              + * + * @param str + * the String to be unwrapped, can be null + * @param wrapToken + * the String used to unwrap + * @return unwrapped String or the original string + * if it is not quoted properly with the wrapToken + * @since 3.6 + */ + public static String unwrap(final String str, final String wrapToken) { + if (isEmpty(str) || isEmpty(wrapToken)) { + return str; + } + + if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) { + final int startIndex = str.indexOf(wrapToken); + final int endIndex = str.lastIndexOf(wrapToken); + final int wrapLength = wrapToken.length(); + if (startIndex != -1 && endIndex != -1) { + return str.substring(startIndex + wrapLength, endIndex); + } + } + + return str; + } + + /** + *

              + * Unwraps a given string from a character. + *

              + * + *
              +     * StringUtils.unwrap(null, null)         = null
              +     * StringUtils.unwrap(null, '\0')         = null
              +     * StringUtils.unwrap(null, '1')          = null
              +     * StringUtils.unwrap("\'abc\'", '\'')    = "abc"
              +     * StringUtils.unwrap("AABabcBAA", 'A')  = "ABabcBA"
              +     * StringUtils.unwrap("A", '#')           = "A"
              +     * StringUtils.unwrap("#A", '#')          = "#A"
              +     * StringUtils.unwrap("A#", '#')          = "A#"
              +     * 
              + * + * @param str + * the String to be unwrapped, can be null + * @param wrapChar + * the character used to unwrap + * @return unwrapped String or the original string + * if it is not quoted properly with the wrapChar + * @since 3.6 + */ + public static String unwrap(final String str, final char wrapChar) { + if (isEmpty(str) || wrapChar == '\0') { + return str; + } + + if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) { + final int startIndex = 0; + final int endIndex = str.length() - 1; + if (startIndex != -1 && endIndex != -1) { + return str.substring(startIndex + 1, endIndex); + } + } + + return str; + } + + /** + *

              Converts a {@code CharSequence} into an array of code points.

              + * + *

              Valid pairs of surrogate code units will be converted into a single supplementary + * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or + * a low surrogate not preceeded by a high surrogate) will be returned as-is.

              + * + *
              +     * StringUtils.toCodePoints(null)   =  null
              +     * StringUtils.toCodePoints("")     =  []  // empty array
              +     * 
              + * + * @param str the character sequence to convert + * @return an array of code points + * @since 3.6 + */ + public static int[] toCodePoints(CharSequence str) { + if (str == null) { + return null; + } + if (str.length() == 0) { + return ArrayUtils.EMPTY_INT_ARRAY; + } + + String s = str.toString(); + int[] result = new int[s.codePointCount(0, s.length())]; + int index = 0; + for (int i = 0; i < result.length; i++) { + result[i] = s.codePointAt(index); + index += Character.charCount(result[i]); + } + return result; + } +} diff --git a/src/org/apache/commons/lang3/SystemUtils.java b/src/org/apache/commons/lang3/SystemUtils.java new file mode 100644 index 0000000..f553618 --- /dev/null +++ b/src/org/apache/commons/lang3/SystemUtils.java @@ -0,0 +1,1740 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.File; + +/** + *

              + * Helpers for {@code java.lang.System}. + *

              + *

              + * If a system property cannot be read due to security restrictions, the corresponding field in this class will be set + * to {@code null} and a message will be written to {@code System.err}. + *

              + *

              + * #ThreadSafe# + *

              + * + * @since 1.0 + */ +public class SystemUtils { + + /** + * The prefix String for all Windows OS. + */ + private static final String OS_NAME_WINDOWS_PREFIX = "Windows"; + + // System property constants + // ----------------------------------------------------------------------- + // These MUST be declared first. Other constants depend on this. + + /** + * The System property key for the user home directory. + */ + private static final String USER_HOME_KEY = "user.home"; + + /** + * The System property key for the user directory. + */ + private static final String USER_DIR_KEY = "user.dir"; + + /** + * The System property key for the Java IO temporary directory. + */ + private static final String JAVA_IO_TMPDIR_KEY = "java.io.tmpdir"; + + /** + * The System property key for the Java home directory. + */ + private static final String JAVA_HOME_KEY = "java.home"; + + /** + *

              + * The {@code awt.toolkit} System Property. + *

              + *

              + * Holds a class name, on Windows XP this is {@code sun.awt.windows.WToolkit}. + *

              + *

              + * On platforms without a GUI, this value is {@code null}. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.1 + */ + public static final String AWT_TOOLKIT = getSystemProperty("awt.toolkit"); + + /** + *

              + * The {@code file.encoding} System Property. + *

              + *

              + * File encoding, such as {@code Cp1252}. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.0 + * @since Java 1.2 + */ + public static final String FILE_ENCODING = getSystemProperty("file.encoding"); + + /** + *

              + * The {@code file.separator} System Property. + * The file separator is: + *

              + *
                + *
              • {@code "/"} on UNIX
              • + *
              • {@code "\"} on Windows.
              • + *
              + * + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @deprecated Use {@link File#separator}, since it is guaranteed to be a + * string containing a single character and it does not require a privilege check. + * @since Java 1.1 + */ + @Deprecated + public static final String FILE_SEPARATOR = getSystemProperty("file.separator"); + + /** + *

              + * The {@code java.awt.fonts} System Property. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.1 + */ + public static final String JAVA_AWT_FONTS = getSystemProperty("java.awt.fonts"); + + /** + *

              + * The {@code java.awt.graphicsenv} System Property. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.1 + */ + public static final String JAVA_AWT_GRAPHICSENV = getSystemProperty("java.awt.graphicsenv"); + + /** + *

              + * The {@code java.awt.headless} System Property. The value of this property is the String {@code "true"} or + * {@code "false"}. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @see #isJavaAwtHeadless() + * @since 2.1 + * @since Java 1.4 + */ + public static final String JAVA_AWT_HEADLESS = getSystemProperty("java.awt.headless"); + + /** + *

              + * The {@code java.awt.printerjob} System Property. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.1 + */ + public static final String JAVA_AWT_PRINTERJOB = getSystemProperty("java.awt.printerjob"); + + /** + *

              + * The {@code java.class.path} System Property. Java class path. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String JAVA_CLASS_PATH = getSystemProperty("java.class.path"); + + /** + *

              + * The {@code java.class.version} System Property. Java class format version number. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String JAVA_CLASS_VERSION = getSystemProperty("java.class.version"); + + /** + *

              + * The {@code java.compiler} System Property. Name of JIT compiler to use. First in JDK version 1.2. Not used in Sun + * JDKs after 1.2. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2. Not used in Sun versions after 1.2. + */ + public static final String JAVA_COMPILER = getSystemProperty("java.compiler"); + + /** + *

              + * The {@code java.endorsed.dirs} System Property. Path of endorsed directory or directories. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.4 + */ + public static final String JAVA_ENDORSED_DIRS = getSystemProperty("java.endorsed.dirs"); + + /** + *

              + * The {@code java.ext.dirs} System Property. Path of extension directory or directories. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.3 + */ + public static final String JAVA_EXT_DIRS = getSystemProperty("java.ext.dirs"); + + /** + *

              + * The {@code java.home} System Property. Java installation directory. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String JAVA_HOME = getSystemProperty(JAVA_HOME_KEY); + + /** + *

              + * The {@code java.io.tmpdir} System Property. Default temp file path. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_IO_TMPDIR = getSystemProperty(JAVA_IO_TMPDIR_KEY); + + /** + *

              + * The {@code java.library.path} System Property. List of paths to search when loading libraries. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_LIBRARY_PATH = getSystemProperty("java.library.path"); + + /** + *

              + * The {@code java.runtime.name} System Property. Java Runtime Environment name. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.0 + * @since Java 1.3 + */ + public static final String JAVA_RUNTIME_NAME = getSystemProperty("java.runtime.name"); + + /** + *

              + * The {@code java.runtime.version} System Property. Java Runtime Environment version. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.0 + * @since Java 1.3 + */ + public static final String JAVA_RUNTIME_VERSION = getSystemProperty("java.runtime.version"); + + /** + *

              + * The {@code java.specification.name} System Property. Java Runtime Environment specification name. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_SPECIFICATION_NAME = getSystemProperty("java.specification.name"); + + /** + *

              + * The {@code java.specification.vendor} System Property. Java Runtime Environment specification vendor. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_SPECIFICATION_VENDOR = getSystemProperty("java.specification.vendor"); + + /** + *

              + * The {@code java.specification.version} System Property. Java Runtime Environment specification version. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.3 + */ + public static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version"); + private static final JavaVersion JAVA_SPECIFICATION_VERSION_AS_ENUM = JavaVersion.get(JAVA_SPECIFICATION_VERSION); + + /** + *

              + * The {@code java.util.prefs.PreferencesFactory} System Property. A class name. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.1 + * @since Java 1.4 + */ + public static final String JAVA_UTIL_PREFS_PREFERENCES_FACTORY = + getSystemProperty("java.util.prefs.PreferencesFactory"); + + /** + *

              + * The {@code java.vendor} System Property. Java vendor-specific string. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String JAVA_VENDOR = getSystemProperty("java.vendor"); + + /** + *

              + * The {@code java.vendor.url} System Property. Java vendor URL. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String JAVA_VENDOR_URL = getSystemProperty("java.vendor.url"); + + /** + *

              + * The {@code java.version} System Property. Java version number. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String JAVA_VERSION = getSystemProperty("java.version"); + + /** + *

              + * The {@code java.vm.info} System Property. Java Virtual Machine implementation info. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.0 + * @since Java 1.2 + */ + public static final String JAVA_VM_INFO = getSystemProperty("java.vm.info"); + + /** + *

              + * The {@code java.vm.name} System Property. Java Virtual Machine implementation name. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_VM_NAME = getSystemProperty("java.vm.name"); + + /** + *

              + * The {@code java.vm.specification.name} System Property. Java Virtual Machine specification name. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_VM_SPECIFICATION_NAME = getSystemProperty("java.vm.specification.name"); + + /** + *

              + * The {@code java.vm.specification.vendor} System Property. Java Virtual Machine specification vendor. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_VM_SPECIFICATION_VENDOR = getSystemProperty("java.vm.specification.vendor"); + + /** + *

              + * The {@code java.vm.specification.version} System Property. Java Virtual Machine specification version. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_VM_SPECIFICATION_VERSION = getSystemProperty("java.vm.specification.version"); + + /** + *

              + * The {@code java.vm.vendor} System Property. Java Virtual Machine implementation vendor. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_VM_VENDOR = getSystemProperty("java.vm.vendor"); + + /** + *

              + * The {@code java.vm.version} System Property. Java Virtual Machine implementation version. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.2 + */ + public static final String JAVA_VM_VERSION = getSystemProperty("java.vm.version"); + + /** + *

              + * The {@code line.separator} System Property. Line separator ("\n" on UNIX). + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @deprecated Use {@link System#lineSeparator} instead, since it does not require a privilege check. + * @since Java 1.1 + */ + @Deprecated + public static final String LINE_SEPARATOR = getSystemProperty("line.separator"); + + /** + *

              + * The {@code os.arch} System Property. Operating system architecture. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String OS_ARCH = getSystemProperty("os.arch"); + + /** + *

              + * The {@code os.name} System Property. Operating system name. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String OS_NAME = getSystemProperty("os.name"); + + /** + *

              + * The {@code os.version} System Property. Operating system version. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String OS_VERSION = getSystemProperty("os.version"); + + /** + *

              + * The {@code path.separator} System Property. Path separator (":" on UNIX). + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @deprecated Use {@link File#pathSeparator}, since it is guaranteed to be a + * string containing a single character and it does not require a privilege check. + * @since Java 1.1 + */ + @Deprecated + public static final String PATH_SEPARATOR = getSystemProperty("path.separator"); + + /** + *

              + * The {@code user.country} or {@code user.region} System Property. User's country code, such as {@code GB}. First + * in Java version 1.2 as {@code user.region}. Renamed to {@code user.country} in 1.4 + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.0 + * @since Java 1.2 + */ + public static final String USER_COUNTRY = getSystemProperty("user.country") == null ? + getSystemProperty("user.region") : getSystemProperty("user.country"); + + /** + *

              + * The {@code user.dir} System Property. User's current working directory. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String USER_DIR = getSystemProperty(USER_DIR_KEY); + + /** + *

              + * The {@code user.home} System Property. User's home directory. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String USER_HOME = getSystemProperty(USER_HOME_KEY); + + /** + *

              + * The {@code user.language} System Property. User's language code, such as {@code "en"}. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.0 + * @since Java 1.2 + */ + public static final String USER_LANGUAGE = getSystemProperty("user.language"); + + /** + *

              + * The {@code user.name} System Property. User's account name. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since Java 1.1 + */ + public static final String USER_NAME = getSystemProperty("user.name"); + + /** + *

              + * The {@code user.timezone} System Property. For example: {@code "America/Los_Angeles"}. + *

              + *

              + * Defaults to {@code null} if the runtime does not have security access to read this property or the property does + * not exist. + *

              + *

              + * This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or + * {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of + * sync with that System property. + *

              + * + * @since 2.1 + */ + public static final String USER_TIMEZONE = getSystemProperty("user.timezone"); + + // Java version checks + // ----------------------------------------------------------------------- + // These MUST be declared after those above as they depend on the + // values being set up + + /** + *

              + * Is {@code true} if this is Java version 1.1 (also 1.1.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + */ + public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1"); + + /** + *

              + * Is {@code true} if this is Java version 1.2 (also 1.2.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + */ + public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2"); + + /** + *

              + * Is {@code true} if this is Java version 1.3 (also 1.3.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + */ + public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3"); + + /** + *

              + * Is {@code true} if this is Java version 1.4 (also 1.4.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + */ + public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4"); + + /** + *

              + * Is {@code true} if this is Java version 1.5 (also 1.5.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + */ + public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5"); + + /** + *

              + * Is {@code true} if this is Java version 1.6 (also 1.6.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + */ + public static final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6"); + + /** + *

              + * Is {@code true} if this is Java version 1.7 (also 1.7.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + * + * @since 3.0 + */ + public static final boolean IS_JAVA_1_7 = getJavaVersionMatches("1.7"); + + /** + *

              + * Is {@code true} if this is Java version 1.8 (also 1.8.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + * + * @since 3.3.2 + */ + public static final boolean IS_JAVA_1_8 = getJavaVersionMatches("1.8"); + + /** + *

              + * Is {@code true} if this is Java version 1.9 (also 1.9.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + * + * @since 3.4 + * + * @deprecated As of release 3.5, replaced by {@link #IS_JAVA_9} + */ + @Deprecated + public static final boolean IS_JAVA_1_9 = getJavaVersionMatches("9"); + + /** + *

              + * Is {@code true} if this is Java version 9 (also 9.x versions). + *

              + *

              + * The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}. + *

              + * + * @since 3.5 + */ + public static final boolean IS_JAVA_9 = getJavaVersionMatches("9"); + + // Operating system checks + // ----------------------------------------------------------------------- + // These MUST be declared after those above as they depend on the + // values being set up + // OS names from http://www.vamphq.com/os.html + // Selected ones included - please advise dev@commons.apache.org + // if you want another added or a mistake corrected + + /** + *

              + * Is {@code true} if this is AIX. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_AIX = getOSMatchesName("AIX"); + + /** + *

              + * Is {@code true} if this is HP-UX. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_HP_UX = getOSMatchesName("HP-UX"); + + /** + *

              + * Is {@code true} if this is IBM OS/400. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.3 + */ + public static final boolean IS_OS_400 = getOSMatchesName("OS/400"); + + /** + *

              + * Is {@code true} if this is Irix. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_IRIX = getOSMatchesName("Irix"); + + /** + *

              + * Is {@code true} if this is Linux. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_LINUX = getOSMatchesName("Linux") || getOSMatchesName("LINUX"); + + /** + *

              + * Is {@code true} if this is Mac. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_MAC = getOSMatchesName("Mac"); + + /** + *

              + * Is {@code true} if this is Mac. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_MAC_OSX = getOSMatchesName("Mac OS X"); + + /** + *

              + * Is {@code true} if this is Mac OS X Cheetah. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_CHEETAH = getOSMatches("Mac OS X", "10.0"); + + /** + *

              + * Is {@code true} if this is Mac OS X Puma. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_PUMA = getOSMatches("Mac OS X", "10.1"); + + /** + *

              + * Is {@code true} if this is Mac OS X Jaguar. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_JAGUAR = getOSMatches("Mac OS X", "10.2"); + + /** + *

              + * Is {@code true} if this is Mac OS X Panther. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_PANTHER = getOSMatches("Mac OS X", "10.3"); + + /** + *

              + * Is {@code true} if this is Mac OS X Tiger. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_TIGER = getOSMatches("Mac OS X", "10.4"); + + /** + *

              + * Is {@code true} if this is Mac OS X Leopard. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_LEOPARD = getOSMatches("Mac OS X", "10.5"); + + /** + *

              + * Is {@code true} if this is Mac OS X Snow Leopard. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_SNOW_LEOPARD = getOSMatches("Mac OS X", "10.6"); + + /** + *

              + * Is {@code true} if this is Mac OS X Lion. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_LION = getOSMatches("Mac OS X", "10.7"); + + /** + *

              + * Is {@code true} if this is Mac OS X Mountain Lion. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_MOUNTAIN_LION = getOSMatches("Mac OS X", "10.8"); + + /** + *

              + * Is {@code true} if this is Mac OS X Mavericks. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_MAVERICKS = getOSMatches("Mac OS X", "10.9"); + + /** + *

              + * Is {@code true} if this is Mac OS X Yosemite. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_MAC_OSX_YOSEMITE = getOSMatches("Mac OS X", "10.10"); + + /** + *

              + * Is {@code true} if this is Mac OS X El Capitan. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.5 + */ + public static final boolean IS_OS_MAC_OSX_EL_CAPITAN = getOSMatches("Mac OS X", "10.11"); + + /** + *

              + * Is {@code true} if this is FreeBSD. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.1 + */ + public static final boolean IS_OS_FREE_BSD = getOSMatchesName("FreeBSD"); + + /** + *

              + * Is {@code true} if this is OpenBSD. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.1 + */ + public static final boolean IS_OS_OPEN_BSD = getOSMatchesName("OpenBSD"); + + /** + *

              + * Is {@code true} if this is NetBSD. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.1 + */ + public static final boolean IS_OS_NET_BSD = getOSMatchesName("NetBSD"); + + /** + *

              + * Is {@code true} if this is OS/2. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_OS2 = getOSMatchesName("OS/2"); + + /** + *

              + * Is {@code true} if this is Solaris. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_SOLARIS = getOSMatchesName("Solaris"); + + /** + *

              + * Is {@code true} if this is SunOS. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_SUN_OS = getOSMatchesName("SunOS"); + + /** + *

              + * Is {@code true} if this is a UNIX like system, as in any of AIX, HP-UX, Irix, Linux, MacOSX, Solaris or SUN OS. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.1 + */ + public static final boolean IS_OS_UNIX = IS_OS_AIX || IS_OS_HP_UX || IS_OS_IRIX || IS_OS_LINUX || IS_OS_MAC_OSX + || IS_OS_SOLARIS || IS_OS_SUN_OS || IS_OS_FREE_BSD || IS_OS_OPEN_BSD || IS_OS_NET_BSD; + + /** + *

              + * Is {@code true} if this is Windows. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX); + + /** + *

              + * Is {@code true} if this is Windows 2000. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_2000 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " 2000"); + + /** + *

              + * Is {@code true} if this is Windows 2003. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.1 + */ + public static final boolean IS_OS_WINDOWS_2003 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " 2003"); + + /** + *

              + * Is {@code true} if this is Windows Server 2008. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.1 + */ + public static final boolean IS_OS_WINDOWS_2008 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " Server 2008"); + + /** + *

              + * Is {@code true} if this is Windows Server 2012. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.4 + */ + public static final boolean IS_OS_WINDOWS_2012 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " Server 2012"); + + /** + *

              + * Is {@code true} if this is Windows 95. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_95 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " 95"); + + /** + *

              + * Is {@code true} if this is Windows 98. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_98 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " 98"); + + /** + *

              + * Is {@code true} if this is Windows ME. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_ME = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " Me"); + + /** + *

              + * Is {@code true} if this is Windows NT. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_NT = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " NT"); + + /** + *

              + * Is {@code true} if this is Windows XP. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.0 + */ + public static final boolean IS_OS_WINDOWS_XP = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " XP"); + + // ----------------------------------------------------------------------- + /** + *

              + * Is {@code true} if this is Windows Vista. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 2.4 + */ + public static final boolean IS_OS_WINDOWS_VISTA = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " Vista"); + + /** + *

              + * Is {@code true} if this is Windows 7. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.0 + */ + public static final boolean IS_OS_WINDOWS_7 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " 7"); + + /** + *

              + * Is {@code true} if this is Windows 8. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.2 + */ + public static final boolean IS_OS_WINDOWS_8 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " 8"); + + /** + *

              + * Is {@code true} if this is Windows 10. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.5 + */ + public static final boolean IS_OS_WINDOWS_10 = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " 10"); + + /** + *

              + * Is {@code true} if this is z/OS. + *

              + *

              + * The field will return {@code false} if {@code OS_NAME} is {@code null}. + *

              + * + * @since 3.5 + */ + // Values on a z/OS system I tested (Gary Gregory - 2016-03-12) + // os.arch = s390x + // os.encoding = ISO8859_1 + // os.name = z/OS + // os.version = 02.02.00 + public static final boolean IS_OS_ZOS = getOSMatchesName("z/OS"); + + /** + *

              + * Gets the Java home directory as a {@code File}. + *

              + * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getJavaHome() { + return new File(System.getProperty(JAVA_HOME_KEY)); + } + + /** + * Gets the host name from an environment variable. + * + *

              + * If you want to know what the network stack says is the host name, you should use {@code InetAddress.getLocalHost().getHostName()}. + *

              + * + * @return the host name. + * @since 3.6 + */ + public static String getHostName() { + return SystemUtils.IS_OS_WINDOWS ? System.getenv("COMPUTERNAME") : System.getenv("HOSTNAME"); + } + + /** + *

              + * Gets the Java IO temporary directory as a {@code File}. + *

              + * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getJavaIoTmpDir() { + return new File(System.getProperty(JAVA_IO_TMPDIR_KEY)); + } + + /** + *

              + * Decides if the Java version matches. + *

              + * + * @param versionPrefix the prefix for the java version + * @return true if matches, or false if not or can't determine + */ + private static boolean getJavaVersionMatches(final String versionPrefix) { + return isJavaVersionMatch(JAVA_SPECIFICATION_VERSION, versionPrefix); + } + + /** + * Decides if the operating system matches. + * + * @param osNamePrefix the prefix for the os name + * @param osVersionPrefix the prefix for the version + * @return true if matches, or false if not or can't determine + */ + private static boolean getOSMatches(final String osNamePrefix, final String osVersionPrefix) { + return isOSMatch(OS_NAME, OS_VERSION, osNamePrefix, osVersionPrefix); + } + + /** + * Decides if the operating system matches. + * + * @param osNamePrefix the prefix for the os name + * @return true if matches, or false if not or can't determine + */ + private static boolean getOSMatchesName(final String osNamePrefix) { + return isOSNameMatch(OS_NAME, osNamePrefix); + } + + // ----------------------------------------------------------------------- + /** + *

              + * Gets a System property, defaulting to {@code null} if the property cannot be read. + *

              + *

              + * If a {@code SecurityException} is caught, the return value is {@code null} and a message is written to + * {@code System.err}. + *

              + * + * @param property the system property name + * @return the system property value or {@code null} if a security problem occurs + */ + private static String getSystemProperty(final String property) { + try { + return System.getProperty(property); + } catch (final SecurityException ex) { + // we are not allowed to look at this property + System.err.println("Caught a SecurityException reading the system property '" + property + + "'; the SystemUtils property value will default to null."); + return null; + } + } + + /** + *

              + * Gets the user directory as a {@code File}. + *

              + * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getUserDir() { + return new File(System.getProperty(USER_DIR_KEY)); + } + + /** + *

              + * Gets the user home directory as a {@code File}. + *

              + * + * @return a directory + * @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow + * access to the specified system property. + * @see System#getProperty(String) + * @since 2.1 + */ + public static File getUserHome() { + return new File(System.getProperty(USER_HOME_KEY)); + } + + /** + * Returns whether the {@link #JAVA_AWT_HEADLESS} value is {@code true}. + * + * @return {@code true} if {@code JAVA_AWT_HEADLESS} is {@code "true"}, {@code false} otherwise. + * @see #JAVA_AWT_HEADLESS + * @since 2.1 + * @since Java 1.4 + */ + public static boolean isJavaAwtHeadless() { + return Boolean.TRUE.toString().equals(JAVA_AWT_HEADLESS); + } + + /** + *

              + * Is the Java version at least the requested version. + *

              + *

              + * Example input: + *

              + *
                + *
              • {@code 1.2f} to test for Java 1.2
              • + *
              • {@code 1.31f} to test for Java 1.3.1
              • + *
              + * + * @param requiredVersion the required version, for example 1.31f + * @return {@code true} if the actual version is equal or greater than the required version + */ + public static boolean isJavaVersionAtLeast(final JavaVersion requiredVersion) { + return JAVA_SPECIFICATION_VERSION_AS_ENUM.atLeast(requiredVersion); + } + + /** + *

              + * Decides if the Java version matches. + *

              + *

              + * This method is package private instead of private to support unit test invocation. + *

              + * + * @param version the actual Java version + * @param versionPrefix the prefix for the expected Java version + * @return true if matches, or false if not or can't determine + */ + static boolean isJavaVersionMatch(final String version, final String versionPrefix) { + if (version == null) { + return false; + } + return version.startsWith(versionPrefix); + } + + /** + * Decides if the operating system matches. + *

              + * This method is package private instead of private to support unit test invocation. + *

              + * + * @param osName the actual OS name + * @param osVersion the actual OS version + * @param osNamePrefix the prefix for the expected OS name + * @param osVersionPrefix the prefix for the expected OS version + * @return true if matches, or false if not or can't determine + */ + static boolean isOSMatch(final String osName, final String osVersion, final String osNamePrefix, final String osVersionPrefix) { + if (osName == null || osVersion == null) { + return false; + } + return isOSNameMatch(osName, osNamePrefix) && isOSVersionMatch(osVersion, osVersionPrefix); + } + + /** + * Decides if the operating system matches. + *

              + * This method is package private instead of private to support unit test invocation. + *

              + * + * @param osName the actual OS name + * @param osNamePrefix the prefix for the expected OS name + * @return true if matches, or false if not or can't determine + */ + static boolean isOSNameMatch(final String osName, final String osNamePrefix) { + if (osName == null) { + return false; + } + return osName.startsWith(osNamePrefix); + } + + /** + * Decides if the operating system version matches. + *

              + * This method is package private instead of private to support unit test invocation. + *

              + * + * @param osVersion the actual OS version + * @param osVersionPrefix the prefix for the expected OS version + * @return true if matches, or false if not or can't determine + */ + static boolean isOSVersionMatch(final String osVersion, final String osVersionPrefix) { + if (StringUtils.isEmpty(osVersion)) { + return false; + } + // Compare parts of the version string instead of using String.startsWith(String) because otherwise + // osVersionPrefix 10.1 would also match osVersion 10.10 + final String[] versionPrefixParts = osVersionPrefix.split("\\."); + final String[] versionParts = osVersion.split("\\."); + for (int i = 0; i < Math.min(versionPrefixParts.length, versionParts.length); i++) { + if (!versionPrefixParts[i].equals(versionParts[i])) { + return false; + } + } + return true; + } + + // ----------------------------------------------------------------------- + /** + *

              + * SystemUtils instances should NOT be constructed in standard programming. Instead, the class should be used as + * {@code SystemUtils.FILE_SEPARATOR}. + *

              + *

              + * This constructor is public to permit tools that require a JavaBean instance to operate. + *

              + */ + public SystemUtils() { + super(); + } + +} diff --git a/src/org/apache/commons/lang3/ThreadUtils.java b/src/org/apache/commons/lang3/ThreadUtils.java new file mode 100644 index 0000000..93a48b7 --- /dev/null +++ b/src/org/apache/commons/lang3/ThreadUtils.java @@ -0,0 +1,460 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + *

              + * Helpers for {@code java.lang.Thread} and {@code java.lang.ThreadGroup}. + *

              + *

              + * #ThreadSafe# + *

              + * + * @see java.lang.Thread + * @see java.lang.ThreadGroup + * @since 3.5 + */ +public class ThreadUtils { + + /** + * Return the active thread with the specified id if it belong's to the specified thread group. + * + * @param threadId The thread id + * @param threadGroup The thread group + * @return The thread which belongs to a specified thread group and the thread's id match the specified id. + * {@code null} is returned if no such thread exists + * @throws IllegalArgumentException if the specified id is zero or negative or the group is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Thread findThreadById(final long threadId, final ThreadGroup threadGroup) { + if (threadGroup == null) { + throw new IllegalArgumentException("The thread group must not be null"); + } + final Thread thread = findThreadById(threadId); + if(thread != null && threadGroup.equals(thread.getThreadGroup())) { + return thread; + } + return null; + } + + /** + * Return the active thread with the specified id if it belong's to a thread group with the specified group name. + * + * @param threadId The thread id + * @param threadGroupName The thread group name + * @return The threads which belongs to a thread group with the specified group name and the thread's id match the specified id. + * {@code null} is returned if no such thread exists + * @throws IllegalArgumentException if the specified id is zero or negative or the group name is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Thread findThreadById(final long threadId, final String threadGroupName) { + if (threadGroupName == null) { + throw new IllegalArgumentException("The thread group name must not be null"); + } + final Thread thread = findThreadById(threadId); + if(thread != null && thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals(threadGroupName)) { + return thread; + } + return null; + } + + /** + * Return active threads with the specified name if they belong to a specified thread group. + * + * @param threadName The thread name + * @param threadGroup The thread group + * @return The threads which belongs to a thread group and the thread's name match the specified name, + * An empty collection is returned if no such thread exists. The collection returned is always unmodifiable. + * @throws IllegalArgumentException if the specified thread name or group is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreadsByName(final String threadName, final ThreadGroup threadGroup) { + return findThreads(threadGroup, false, new NamePredicate(threadName)); + } + + /** + * Return active threads with the specified name if they belong to a thread group with the specified group name. + * + * @param threadName The thread name + * @param threadGroupName The thread group name + * @return The threads which belongs to a thread group with the specified group name and the thread's name match the specified name, + * An empty collection is returned if no such thread exists. The collection returned is always unmodifiable. + * @throws IllegalArgumentException if the specified thread name or group name is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreadsByName(final String threadName, final String threadGroupName) { + if (threadName == null) { + throw new IllegalArgumentException("The thread name must not be null"); + } + if (threadGroupName == null) { + throw new IllegalArgumentException("The thread group name must not be null"); + } + + final Collection threadGroups = findThreadGroups(new NamePredicate(threadGroupName)); + + if(threadGroups.isEmpty()) { + return Collections.emptyList(); + } + + final Collection result = new ArrayList<>(); + final NamePredicate threadNamePredicate = new NamePredicate(threadName); + for(final ThreadGroup group : threadGroups) { + result.addAll(findThreads(group, false, threadNamePredicate)); + } + return Collections.unmodifiableCollection(result); + } + + /** + * Return active thread groups with the specified group name. + * + * @param threadGroupName The thread group name + * @return the thread groups with the specified group name or an empty collection if no such thread group exists. The collection returned is always unmodifiable. + * @throws IllegalArgumentException if group name is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreadGroupsByName(final String threadGroupName) { + return findThreadGroups(new NamePredicate(threadGroupName)); + } + + /** + * Return all active thread groups excluding the system thread group (A thread group is active if it has been not destroyed). + * + * @return all thread groups excluding the system thread group. The collection returned is always unmodifiable. + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection getAllThreadGroups() { + return findThreadGroups(ALWAYS_TRUE_PREDICATE); + } + + /** + * Return the system thread group (sometimes also referred as "root thread group"). + * + * @return the system thread group + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static ThreadGroup getSystemThreadGroup() { + ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); + while(threadGroup.getParent() != null) { + threadGroup = threadGroup.getParent(); + } + return threadGroup; + } + + /** + * Return all active threads (A thread is active if it has been started and has not yet died). + * + * @return all active threads. The collection returned is always unmodifiable. + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection getAllThreads() { + return findThreads(ALWAYS_TRUE_PREDICATE); + } + + /** + * Return active threads with the specified name. + * + * @param threadName The thread name + * @return The threads with the specified name or an empty collection if no such thread exists. The collection returned is always unmodifiable. + * @throws IllegalArgumentException if the specified name is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreadsByName(final String threadName) { + return findThreads(new NamePredicate(threadName)); + } + + /** + * Return the active thread with the specified id. + * + * @param threadId The thread id + * @return The thread with the specified id or {@code null} if no such thread exists + * @throws IllegalArgumentException if the specified id is zero or negative + * @throws SecurityException + * if the current thread cannot access the system thread group + * + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Thread findThreadById(final long threadId) { + final Collection result = findThreads(new ThreadIdPredicate(threadId)); + return result.isEmpty() ? null : result.iterator().next(); + } + + /** + *

              + * ThreadUtils instances should NOT be constructed in standard programming. Instead, the class should be used as + * {@code ThreadUtils.getAllThreads()} + *

              + *

              + * This constructor is public to permit tools that require a JavaBean instance to operate. + *

              + */ + public ThreadUtils() { + super(); + } + + /** + * A predicate for selecting threads. + */ + //if java minimal version for lang becomes 1.8 extend this interface from java.util.function.Predicate + public interface ThreadPredicate /*extends java.util.function.Predicate*/{ + + /** + * Evaluates this predicate on the given thread. + * @param thread the thread + * @return {@code true} if the thread matches the predicate, otherwise {@code false} + */ + boolean test(Thread thread); + } + + /** + * A predicate for selecting threadgroups. + */ + //if java minimal version for lang becomes 1.8 extend this interface from java.util.function.Predicate + public interface ThreadGroupPredicate /*extends java.util.function.Predicate*/{ + + /** + * Evaluates this predicate on the given threadgroup. + * @param threadGroup the threadgroup + * @return {@code true} if the threadGroup matches the predicate, otherwise {@code false} + */ + boolean test(ThreadGroup threadGroup); + } + + /** + * Predicate which always returns true. + */ + public static final AlwaysTruePredicate ALWAYS_TRUE_PREDICATE = new AlwaysTruePredicate(); + + /** + * A predicate implementation which always returns true. + */ + private final static class AlwaysTruePredicate implements ThreadPredicate, ThreadGroupPredicate{ + + private AlwaysTruePredicate() { + } + + @Override + public boolean test(final ThreadGroup threadGroup) { + return true; + } + + @Override + public boolean test(final Thread thread) { + return true; + } + } + + /** + * A predicate implementation which matches a thread or threadgroup name. + */ + public static class NamePredicate implements ThreadPredicate, ThreadGroupPredicate { + + private final String name; + + /** + * Predicate constructor + * + * @param name thread or threadgroup name + * @throws IllegalArgumentException if the name is {@code null} + */ + public NamePredicate(final String name) { + super(); + if (name == null) { + throw new IllegalArgumentException("The name must not be null"); + } + this.name = name; + } + + @Override + public boolean test(final ThreadGroup threadGroup) { + return threadGroup != null && threadGroup.getName().equals(name); + } + + @Override + public boolean test(final Thread thread) { + return thread != null && thread.getName().equals(name); + } + } + + /** + * A predicate implementation which matches a thread id. + */ + public static class ThreadIdPredicate implements ThreadPredicate { + + private final long threadId; + + /** + * Predicate constructor + * + * @param threadId the threadId to match + * @throws IllegalArgumentException if the threadId is zero or negative + */ + public ThreadIdPredicate(final long threadId) { + super(); + if (threadId <= 0) { + throw new IllegalArgumentException("The thread id must be greater than zero"); + } + this.threadId = threadId; + } + + @Override + public boolean test(final Thread thread) { + return thread != null && thread.getId() == threadId; + } + } + + /** + * Select all active threads which match the given predicate. + * + * @param predicate the predicate + * @return An unmodifiable {@code Collection} of active threads matching the given predicate + * + * @throws IllegalArgumentException if the predicate is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreads(final ThreadPredicate predicate){ + return findThreads(getSystemThreadGroup(), true, predicate); + } + + /** + * Select all active threadgroups which match the given predicate. + * + * @param predicate the predicate + * @return An unmodifiable {@code Collection} of active threadgroups matching the given predicate + * @throws IllegalArgumentException if the predicate is null + * @throws SecurityException + * if the current thread cannot access the system thread group + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreadGroups(final ThreadGroupPredicate predicate){ + return findThreadGroups(getSystemThreadGroup(), true, predicate); + } + + /** + * Select all active threads which match the given predicate and which belongs to the given thread group (or one of its subgroups). + * + * @param group the thread group + * @param recurse if {@code true} then evaluate the predicate recursively on all threads in all subgroups of the given group + * @param predicate the predicate + * @return An unmodifiable {@code Collection} of active threads which match the given predicate and which belongs to the given thread group + * @throws IllegalArgumentException if the given group or predicate is null + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreads(final ThreadGroup group, final boolean recurse, final ThreadPredicate predicate) { + if (group == null) { + throw new IllegalArgumentException("The group must not be null"); + } + if (predicate == null) { + throw new IllegalArgumentException("The predicate must not be null"); + } + + int count = group.activeCount(); + Thread[] threads; + do { + threads = new Thread[count + (count / 2) + 1]; //slightly grow the array size + count = group.enumerate(threads, recurse); + //return value of enumerate() must be strictly less than the array size according to javadoc + } while (count >= threads.length); + + final List result = new ArrayList<>(count); + for (int i = 0; i < count; ++i) { + if (predicate.test(threads[i])) { + result.add(threads[i]); + } + } + return Collections.unmodifiableCollection(result); + } + + /** + * Select all active threadgroups which match the given predicate and which is a subgroup of the given thread group (or one of its subgroups). + * + * @param group the thread group + * @param recurse if {@code true} then evaluate the predicate recursively on all threadgroups in all subgroups of the given group + * @param predicate the predicate + * @return An unmodifiable {@code Collection} of active threadgroups which match the given predicate and which is a subgroup of the given thread group + * @throws IllegalArgumentException if the given group or predicate is null + * @throws SecurityException if the current thread cannot modify + * thread groups from this thread's thread group up to the system thread group + */ + public static Collection findThreadGroups(final ThreadGroup group, final boolean recurse, final ThreadGroupPredicate predicate){ + if (group == null) { + throw new IllegalArgumentException("The group must not be null"); + } + if (predicate == null) { + throw new IllegalArgumentException("The predicate must not be null"); + } + + int count = group.activeGroupCount(); + ThreadGroup[] threadGroups; + do { + threadGroups = new ThreadGroup[count + (count / 2) + 1]; //slightly grow the array size + count = group.enumerate(threadGroups, recurse); + //return value of enumerate() must be strictly less than the array size according to javadoc + } while(count >= threadGroups.length); + + final List result = new ArrayList<>(count); + for(int i = 0; i < count; ++i) { + if(predicate.test(threadGroups[i])) { + result.add(threadGroups[i]); + } + } + return Collections.unmodifiableCollection(result); + } +} diff --git a/src/org/apache/commons/lang3/Validate.java b/src/org/apache/commons/lang3/Validate.java new file mode 100644 index 0000000..f6e4983 --- /dev/null +++ b/src/org/apache/commons/lang3/Validate.java @@ -0,0 +1,1320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.regex.Pattern; + +/** + *

              This class assists in validating arguments. The validation methods are + * based along the following principles: + *

                + *
              • An invalid {@code null} argument causes a {@link NullPointerException}.
              • + *
              • A non-{@code null} argument causes an {@link IllegalArgumentException}.
              • + *
              • An invalid index into an array/collection/map/string causes an {@link IndexOutOfBoundsException}.
              • + *
              + * + *

              All exceptions messages are + * format strings + * as defined by the Java platform. For example:

              + * + *
              + * Validate.isTrue(i > 0, "The value must be greater than zero: %d", i);
              + * Validate.notNull(surname, "The surname must not be %s", null);
              + * 
              + * + *

              #ThreadSafe#

              + * @see java.lang.String#format(String, Object...) + * @since 2.0 + */ +public class Validate { + + private static final String DEFAULT_NOT_NAN_EX_MESSAGE = + "The validated value is not a number"; + private static final String DEFAULT_FINITE_EX_MESSAGE = + "The value is invalid: %f"; + private static final String DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE = + "The value %s is not in the specified exclusive range of %s to %s"; + private static final String DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE = + "The value %s is not in the specified inclusive range of %s to %s"; + private static final String DEFAULT_MATCHES_PATTERN_EX = "The string %s does not match the pattern %s"; + private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null"; + private static final String DEFAULT_IS_TRUE_EX_MESSAGE = "The validated expression is false"; + private static final String DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE = + "The validated array contains null element at index: %d"; + private static final String DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE = + "The validated collection contains null element at index: %d"; + private static final String DEFAULT_NOT_BLANK_EX_MESSAGE = "The validated character sequence is blank"; + private static final String DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE = "The validated array is empty"; + private static final String DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE = + "The validated character sequence is empty"; + private static final String DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE = "The validated collection is empty"; + private static final String DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE = "The validated map is empty"; + private static final String DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE = "The validated array index is invalid: %d"; + private static final String DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE = + "The validated character sequence index is invalid: %d"; + private static final String DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE = + "The validated collection index is invalid: %d"; + private static final String DEFAULT_VALID_STATE_EX_MESSAGE = "The validated state is false"; + private static final String DEFAULT_IS_ASSIGNABLE_EX_MESSAGE = "Cannot assign a %s to a %s"; + private static final String DEFAULT_IS_INSTANCE_OF_EX_MESSAGE = "Expected type: %s, actual: %s"; + + /** + * Constructor. This class should not normally be instantiated. + */ + public Validate() { + super(); + } + + // isTrue + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the argument condition is {@code true}; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

              + * + *
              Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);
              + * + *

              For performance reasons, the long value is passed as a separate parameter and + * appended to the exception message only in the case of an error.

              + * + * @param expression the boolean expression to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param value the value to append to the message when invalid + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean) + * @see #isTrue(boolean, String, double) + * @see #isTrue(boolean, String, Object...) + */ + public static void isTrue(final boolean expression, final String message, final long value) { + if (expression == false) { + throw new IllegalArgumentException(String.format(message, Long.valueOf(value))); + } + } + + /** + *

              Validate that the argument condition is {@code true}; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

              + * + *
              Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);
              + * + *

              For performance reasons, the double value is passed as a separate parameter and + * appended to the exception message only in the case of an error.

              + * + * @param expression the boolean expression to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param value the value to append to the message when invalid + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean) + * @see #isTrue(boolean, String, long) + * @see #isTrue(boolean, String, Object...) + */ + public static void isTrue(final boolean expression, final String message, final double value) { + if (expression == false) { + throw new IllegalArgumentException(String.format(message, Double.valueOf(value))); + } + } + + /** + *

              Validate that the argument condition is {@code true}; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

              + * + *
              +     * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
              +     * Validate.isTrue(myObject.isOk(), "The object is not okay");
              + * + * @param expression the boolean expression to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean) + * @see #isTrue(boolean, String, long) + * @see #isTrue(boolean, String, double) + */ + public static void isTrue(final boolean expression, final String message, final Object... values) { + if (expression == false) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + /** + *

              Validate that the argument condition is {@code true}; otherwise + * throwing an exception. This method is useful when validating according + * to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

              + * + *
              +     * Validate.isTrue(i > 0);
              +     * Validate.isTrue(myObject.isOk());
              + * + *

              The message of the exception is "The validated expression is + * false".

              + * + * @param expression the boolean expression to check + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean, String, long) + * @see #isTrue(boolean, String, double) + * @see #isTrue(boolean, String, Object...) + */ + public static void isTrue(final boolean expression) { + if (expression == false) { + throw new IllegalArgumentException(DEFAULT_IS_TRUE_EX_MESSAGE); + } + } + + // notNull + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument is not {@code null}; + * otherwise throwing an exception. + * + *

              Validate.notNull(myObject, "The object must not be null");
              + * + *

              The message of the exception is "The validated object is + * null".

              + * + * @param the object type + * @param object the object to check + * @return the validated object (never {@code null} for method chaining) + * @throws NullPointerException if the object is {@code null} + * @see #notNull(Object, String, Object...) + */ + public static T notNull(final T object) { + return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE); + } + + /** + *

              Validate that the specified argument is not {@code null}; + * otherwise throwing an exception with the specified message. + * + *

              Validate.notNull(myObject, "The object must not be null");
              + * + * @param the object type + * @param object the object to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message + * @return the validated object (never {@code null} for method chaining) + * @throws NullPointerException if the object is {@code null} + * @see #notNull(Object) + */ + public static T notNull(final T object, final String message, final Object... values) { + if (object == null) { + throw new NullPointerException(String.format(message, values)); + } + return object; + } + + // notEmpty array + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument array is neither {@code null} + * nor a length of zero (no elements); otherwise throwing an exception + * with the specified message. + * + *

              Validate.notEmpty(myArray, "The array must not be empty");
              + * + * @param the array type + * @param array the array to check, validated not null by this method + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated array (never {@code null} method for chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IllegalArgumentException if the array is empty + * @see #notEmpty(Object[]) + */ + public static T[] notEmpty(final T[] array, final String message, final Object... values) { + if (array == null) { + throw new NullPointerException(String.format(message, values)); + } + if (array.length == 0) { + throw new IllegalArgumentException(String.format(message, values)); + } + return array; + } + + /** + *

              Validate that the specified argument array is neither {@code null} + * nor a length of zero (no elements); otherwise throwing an exception. + * + *

              Validate.notEmpty(myArray);
              + * + *

              The message in the exception is "The validated array is + * empty". + * + * @param the array type + * @param array the array to check, validated not null by this method + * @return the validated array (never {@code null} method for chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IllegalArgumentException if the array is empty + * @see #notEmpty(Object[], String, Object...) + */ + public static T[] notEmpty(final T[] array) { + return notEmpty(array, DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE); + } + + // notEmpty collection + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument collection is neither {@code null} + * nor a size of zero (no elements); otherwise throwing an exception + * with the specified message. + * + *

              Validate.notEmpty(myCollection, "The collection must not be empty");
              + * + * @param the collection type + * @param collection the collection to check, validated not null by this method + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated collection (never {@code null} method for chaining) + * @throws NullPointerException if the collection is {@code null} + * @throws IllegalArgumentException if the collection is empty + * @see #notEmpty(Object[]) + */ + public static > T notEmpty(final T collection, final String message, final Object... values) { + if (collection == null) { + throw new NullPointerException(String.format(message, values)); + } + if (collection.isEmpty()) { + throw new IllegalArgumentException(String.format(message, values)); + } + return collection; + } + + /** + *

              Validate that the specified argument collection is neither {@code null} + * nor a size of zero (no elements); otherwise throwing an exception. + * + *

              Validate.notEmpty(myCollection);
              + * + *

              The message in the exception is "The validated collection is + * empty".

              + * + * @param the collection type + * @param collection the collection to check, validated not null by this method + * @return the validated collection (never {@code null} method for chaining) + * @throws NullPointerException if the collection is {@code null} + * @throws IllegalArgumentException if the collection is empty + * @see #notEmpty(Collection, String, Object...) + */ + public static > T notEmpty(final T collection) { + return notEmpty(collection, DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE); + } + + // notEmpty map + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument map is neither {@code null} + * nor a size of zero (no elements); otherwise throwing an exception + * with the specified message. + * + *

              Validate.notEmpty(myMap, "The map must not be empty");
              + * + * @param the map type + * @param map the map to check, validated not null by this method + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated map (never {@code null} method for chaining) + * @throws NullPointerException if the map is {@code null} + * @throws IllegalArgumentException if the map is empty + * @see #notEmpty(Object[]) + */ + public static > T notEmpty(final T map, final String message, final Object... values) { + if (map == null) { + throw new NullPointerException(String.format(message, values)); + } + if (map.isEmpty()) { + throw new IllegalArgumentException(String.format(message, values)); + } + return map; + } + + /** + *

              Validate that the specified argument map is neither {@code null} + * nor a size of zero (no elements); otherwise throwing an exception. + * + *

              Validate.notEmpty(myMap);
              + * + *

              The message in the exception is "The validated map is + * empty".

              + * + * @param the map type + * @param map the map to check, validated not null by this method + * @return the validated map (never {@code null} method for chaining) + * @throws NullPointerException if the map is {@code null} + * @throws IllegalArgumentException if the map is empty + * @see #notEmpty(Map, String, Object...) + */ + public static > T notEmpty(final T map) { + return notEmpty(map, DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE); + } + + // notEmpty string + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument character sequence is + * neither {@code null} nor a length of zero (no characters); + * otherwise throwing an exception with the specified message. + * + *

              Validate.notEmpty(myString, "The string must not be empty");
              + * + * @param the character sequence type + * @param chars the character sequence to check, validated not null by this method + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated character sequence (never {@code null} method for chaining) + * @throws NullPointerException if the character sequence is {@code null} + * @throws IllegalArgumentException if the character sequence is empty + * @see #notEmpty(CharSequence) + */ + public static T notEmpty(final T chars, final String message, final Object... values) { + if (chars == null) { + throw new NullPointerException(String.format(message, values)); + } + if (chars.length() == 0) { + throw new IllegalArgumentException(String.format(message, values)); + } + return chars; + } + + /** + *

              Validate that the specified argument character sequence is + * neither {@code null} nor a length of zero (no characters); + * otherwise throwing an exception with the specified message. + * + *

              Validate.notEmpty(myString);
              + * + *

              The message in the exception is "The validated + * character sequence is empty".

              + * + * @param the character sequence type + * @param chars the character sequence to check, validated not null by this method + * @return the validated character sequence (never {@code null} method for chaining) + * @throws NullPointerException if the character sequence is {@code null} + * @throws IllegalArgumentException if the character sequence is empty + * @see #notEmpty(CharSequence, String, Object...) + */ + public static T notEmpty(final T chars) { + return notEmpty(chars, DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE); + } + + // notBlank string + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument character sequence is + * neither {@code null}, a length of zero (no characters), empty + * nor whitespace; otherwise throwing an exception with the specified + * message. + * + *

              Validate.notBlank(myString, "The string must not be blank");
              + * + * @param the character sequence type + * @param chars the character sequence to check, validated not null by this method + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated character sequence (never {@code null} method for chaining) + * @throws NullPointerException if the character sequence is {@code null} + * @throws IllegalArgumentException if the character sequence is blank + * @see #notBlank(CharSequence) + * + * @since 3.0 + */ + public static T notBlank(final T chars, final String message, final Object... values) { + if (chars == null) { + throw new NullPointerException(String.format(message, values)); + } + if (StringUtils.isBlank(chars)) { + throw new IllegalArgumentException(String.format(message, values)); + } + return chars; + } + + /** + *

              Validate that the specified argument character sequence is + * neither {@code null}, a length of zero (no characters), empty + * nor whitespace; otherwise throwing an exception. + * + *

              Validate.notBlank(myString);
              + * + *

              The message in the exception is "The validated character + * sequence is blank".

              + * + * @param the character sequence type + * @param chars the character sequence to check, validated not null by this method + * @return the validated character sequence (never {@code null} method for chaining) + * @throws NullPointerException if the character sequence is {@code null} + * @throws IllegalArgumentException if the character sequence is blank + * @see #notBlank(CharSequence, String, Object...) + * + * @since 3.0 + */ + public static T notBlank(final T chars) { + return notBlank(chars, DEFAULT_NOT_BLANK_EX_MESSAGE); + } + + // noNullElements array + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument array is neither + * {@code null} nor contains any elements that are {@code null}; + * otherwise throwing an exception with the specified message. + * + *

              Validate.noNullElements(myArray, "The array contain null at position %d");
              + * + *

              If the array is {@code null}, then the message in the exception + * is "The validated object is null".

              + * + *

              If the array has a {@code null} element, then the iteration + * index of the invalid element is appended to the {@code values} + * argument.

              + * + * @param the array type + * @param array the array to check, validated not null by this method + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated array (never {@code null} method for chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IllegalArgumentException if an element is {@code null} + * @see #noNullElements(Object[]) + */ + public static T[] noNullElements(final T[] array, final String message, final Object... values) { + Validate.notNull(array); + for (int i = 0; i < array.length; i++) { + if (array[i] == null) { + final Object[] values2 = ArrayUtils.add(values, Integer.valueOf(i)); + throw new IllegalArgumentException(String.format(message, values2)); + } + } + return array; + } + + /** + *

              Validate that the specified argument array is neither + * {@code null} nor contains any elements that are {@code null}; + * otherwise throwing an exception.

              + * + *
              Validate.noNullElements(myArray);
              + * + *

              If the array is {@code null}, then the message in the exception + * is "The validated object is null".

              + * + *

              If the array has a {@code null} element, then the message in the + * exception is "The validated array contains null element at index: + * " followed by the index.

              + * + * @param the array type + * @param array the array to check, validated not null by this method + * @return the validated array (never {@code null} method for chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IllegalArgumentException if an element is {@code null} + * @see #noNullElements(Object[], String, Object...) + */ + public static T[] noNullElements(final T[] array) { + return noNullElements(array, DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE); + } + + // noNullElements iterable + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument iterable is neither + * {@code null} nor contains any elements that are {@code null}; + * otherwise throwing an exception with the specified message. + * + *

              Validate.noNullElements(myCollection, "The collection contains null at position %d");
              + * + *

              If the iterable is {@code null}, then the message in the exception + * is "The validated object is null".

              + * + *

              If the iterable has a {@code null} element, then the iteration + * index of the invalid element is appended to the {@code values} + * argument.

              + * + * @param the iterable type + * @param iterable the iterable to check, validated not null by this method + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated iterable (never {@code null} method for chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IllegalArgumentException if an element is {@code null} + * @see #noNullElements(Iterable) + */ + public static > T noNullElements(final T iterable, final String message, final Object... values) { + Validate.notNull(iterable); + int i = 0; + for (final Iterator it = iterable.iterator(); it.hasNext(); i++) { + if (it.next() == null) { + final Object[] values2 = ArrayUtils.addAll(values, Integer.valueOf(i)); + throw new IllegalArgumentException(String.format(message, values2)); + } + } + return iterable; + } + + /** + *

              Validate that the specified argument iterable is neither + * {@code null} nor contains any elements that are {@code null}; + * otherwise throwing an exception. + * + *

              Validate.noNullElements(myCollection);
              + * + *

              If the iterable is {@code null}, then the message in the exception + * is "The validated object is null".

              + * + *

              If the array has a {@code null} element, then the message in the + * exception is "The validated iterable contains null element at index: + * " followed by the index.

              + * + * @param the iterable type + * @param iterable the iterable to check, validated not null by this method + * @return the validated iterable (never {@code null} method for chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IllegalArgumentException if an element is {@code null} + * @see #noNullElements(Iterable, String, Object...) + */ + public static > T noNullElements(final T iterable) { + return noNullElements(iterable, DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE); + } + + // validIndex array + //--------------------------------------------------------------------------------- + + /** + *

              Validates that the index is within the bounds of the argument + * array; otherwise throwing an exception with the specified message.

              + * + *
              Validate.validIndex(myArray, 2, "The array index is invalid: ");
              + * + *

              If the array is {@code null}, then the message of the exception + * is "The validated object is null".

              + * + * @param the array type + * @param array the array to check, validated not null by this method + * @param index the index to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated array (never {@code null} for method chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IndexOutOfBoundsException if the index is invalid + * @see #validIndex(Object[], int) + * + * @since 3.0 + */ + public static T[] validIndex(final T[] array, final int index, final String message, final Object... values) { + Validate.notNull(array); + if (index < 0 || index >= array.length) { + throw new IndexOutOfBoundsException(String.format(message, values)); + } + return array; + } + + /** + *

              Validates that the index is within the bounds of the argument + * array; otherwise throwing an exception.

              + * + *
              Validate.validIndex(myArray, 2);
              + * + *

              If the array is {@code null}, then the message of the exception + * is "The validated object is null".

              + * + *

              If the index is invalid, then the message of the exception is + * "The validated array index is invalid: " followed by the + * index.

              + * + * @param the array type + * @param array the array to check, validated not null by this method + * @param index the index to check + * @return the validated array (never {@code null} for method chaining) + * @throws NullPointerException if the array is {@code null} + * @throws IndexOutOfBoundsException if the index is invalid + * @see #validIndex(Object[], int, String, Object...) + * + * @since 3.0 + */ + public static T[] validIndex(final T[] array, final int index) { + return validIndex(array, index, DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE, Integer.valueOf(index)); + } + + // validIndex collection + //--------------------------------------------------------------------------------- + + /** + *

              Validates that the index is within the bounds of the argument + * collection; otherwise throwing an exception with the specified message.

              + * + *
              Validate.validIndex(myCollection, 2, "The collection index is invalid: ");
              + * + *

              If the collection is {@code null}, then the message of the + * exception is "The validated object is null".

              + * + * @param the collection type + * @param collection the collection to check, validated not null by this method + * @param index the index to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated collection (never {@code null} for chaining) + * @throws NullPointerException if the collection is {@code null} + * @throws IndexOutOfBoundsException if the index is invalid + * @see #validIndex(Collection, int) + * + * @since 3.0 + */ + public static > T validIndex(final T collection, final int index, final String message, final Object... values) { + Validate.notNull(collection); + if (index < 0 || index >= collection.size()) { + throw new IndexOutOfBoundsException(String.format(message, values)); + } + return collection; + } + + /** + *

              Validates that the index is within the bounds of the argument + * collection; otherwise throwing an exception.

              + * + *
              Validate.validIndex(myCollection, 2);
              + * + *

              If the index is invalid, then the message of the exception + * is "The validated collection index is invalid: " + * followed by the index.

              + * + * @param the collection type + * @param collection the collection to check, validated not null by this method + * @param index the index to check + * @return the validated collection (never {@code null} for method chaining) + * @throws NullPointerException if the collection is {@code null} + * @throws IndexOutOfBoundsException if the index is invalid + * @see #validIndex(Collection, int, String, Object...) + * + * @since 3.0 + */ + public static > T validIndex(final T collection, final int index) { + return validIndex(collection, index, DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE, Integer.valueOf(index)); + } + + // validIndex string + //--------------------------------------------------------------------------------- + + /** + *

              Validates that the index is within the bounds of the argument + * character sequence; otherwise throwing an exception with the + * specified message.

              + * + *
              Validate.validIndex(myStr, 2, "The string index is invalid: ");
              + * + *

              If the character sequence is {@code null}, then the message + * of the exception is "The validated object is null".

              + * + * @param the character sequence type + * @param chars the character sequence to check, validated not null by this method + * @param index the index to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @return the validated character sequence (never {@code null} for method chaining) + * @throws NullPointerException if the character sequence is {@code null} + * @throws IndexOutOfBoundsException if the index is invalid + * @see #validIndex(CharSequence, int) + * + * @since 3.0 + */ + public static T validIndex(final T chars, final int index, final String message, final Object... values) { + Validate.notNull(chars); + if (index < 0 || index >= chars.length()) { + throw new IndexOutOfBoundsException(String.format(message, values)); + } + return chars; + } + + /** + *

              Validates that the index is within the bounds of the argument + * character sequence; otherwise throwing an exception.

              + * + *
              Validate.validIndex(myStr, 2);
              + * + *

              If the character sequence is {@code null}, then the message + * of the exception is "The validated object is + * null".

              + * + *

              If the index is invalid, then the message of the exception + * is "The validated character sequence index is invalid: " + * followed by the index.

              + * + * @param the character sequence type + * @param chars the character sequence to check, validated not null by this method + * @param index the index to check + * @return the validated character sequence (never {@code null} for method chaining) + * @throws NullPointerException if the character sequence is {@code null} + * @throws IndexOutOfBoundsException if the index is invalid + * @see #validIndex(CharSequence, int, String, Object...) + * + * @since 3.0 + */ + public static T validIndex(final T chars, final int index) { + return validIndex(chars, index, DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE, Integer.valueOf(index)); + } + + // validState + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the stateful condition is {@code true}; otherwise + * throwing an exception. This method is useful when validating according + * to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

              + * + *
              +     * Validate.validState(field > 0);
              +     * Validate.validState(this.isOk());
              + * + *

              The message of the exception is "The validated state is + * false".

              + * + * @param expression the boolean expression to check + * @throws IllegalStateException if expression is {@code false} + * @see #validState(boolean, String, Object...) + * + * @since 3.0 + */ + public static void validState(final boolean expression) { + if (expression == false) { + throw new IllegalStateException(DEFAULT_VALID_STATE_EX_MESSAGE); + } + } + + /** + *

              Validate that the stateful condition is {@code true}; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

              + * + *
              Validate.validState(this.isOk(), "The state is not OK: %s", myObject);
              + * + * @param expression the boolean expression to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalStateException if expression is {@code false} + * @see #validState(boolean) + * + * @since 3.0 + */ + public static void validState(final boolean expression, final String message, final Object... values) { + if (expression == false) { + throw new IllegalStateException(String.format(message, values)); + } + } + + // matchesPattern + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument character sequence matches the specified regular + * expression pattern; otherwise throwing an exception.

              + * + *
              Validate.matchesPattern("hi", "[a-z]*");
              + * + *

              The syntax of the pattern is the one used in the {@link Pattern} class.

              + * + * @param input the character sequence to validate, not null + * @param pattern the regular expression pattern, not null + * @throws IllegalArgumentException if the character sequence does not match the pattern + * @see #matchesPattern(CharSequence, String, String, Object...) + * + * @since 3.0 + */ + public static void matchesPattern(final CharSequence input, final String pattern) { + if (Pattern.matches(pattern, input) == false) { + throw new IllegalArgumentException(String.format(DEFAULT_MATCHES_PATTERN_EX, input, pattern)); + } + } + + /** + *

              Validate that the specified argument character sequence matches the specified regular + * expression pattern; otherwise throwing an exception with the specified message.

              + * + *
              Validate.matchesPattern("hi", "[a-z]*", "%s does not match %s", "hi" "[a-z]*");
              + * + *

              The syntax of the pattern is the one used in the {@link Pattern} class.

              + * + * @param input the character sequence to validate, not null + * @param pattern the regular expression pattern, not null + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalArgumentException if the character sequence does not match the pattern + * @see #matchesPattern(CharSequence, String) + * + * @since 3.0 + */ + public static void matchesPattern(final CharSequence input, final String pattern, final String message, final Object... values) { + if (Pattern.matches(pattern, input) == false) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + // notNaN + //--------------------------------------------------------------------------------- + + /** + *

              Validates that the specified argument is not {@code NaN}; otherwise + * throwing an exception.

              + * + *
              Validate.notNaN(myDouble);
              + * + *

              The message of the exception is "The validated value is not a + * number".

              + * + * @param value the value to validate + * @throws IllegalArgumentException if the value is not a number + * @see #notNaN(double, java.lang.String, java.lang.Object...) + * + * @since 3.5 + */ + public static void notNaN(final double value) { + notNaN(value, DEFAULT_NOT_NAN_EX_MESSAGE); + } + + /** + *

              Validates that the specified argument is not {@code NaN}; otherwise + * throwing an exception with the specified message.

              + * + *
              Validate.notNaN(myDouble, "The value must be a number");
              + * + * @param value the value to validate + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message + * @throws IllegalArgumentException if the value is not a number + * @see #notNaN(double) + * + * @since 3.5 + */ + public static void notNaN(final double value, final String message, final Object... values) { + if (Double.isNaN(value)) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + // finite + //--------------------------------------------------------------------------------- + + /** + *

              Validates that the specified argument is not infinite or {@code NaN}; + * otherwise throwing an exception.

              + * + *
              Validate.finite(myDouble);
              + * + *

              The message of the exception is "The value is invalid: %f".

              + * + * @param value the value to validate + * @throws IllegalArgumentException if the value is infinite or {@code NaN} + * @see #finite(double, java.lang.String, java.lang.Object...) + * + * @since 3.5 + */ + public static void finite(final double value) { + finite(value, DEFAULT_FINITE_EX_MESSAGE, value); + } + + /** + *

              Validates that the specified argument is not infinite or {@code NaN}; + * otherwise throwing an exception with the specified message.

              + * + *
              Validate.finite(myDouble, "The argument must contain a numeric value");
              + * + * @param value the value to validate + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message + * @throws IllegalArgumentException if the value is infinite or {@code NaN} + * @see #finite(double) + * + * @since 3.5 + */ + public static void finite(final double value, final String message, final Object... values) { + if (Double.isNaN(value) || Double.isInfinite(value)) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + // inclusiveBetween + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument object fall between the two + * inclusive values specified; otherwise, throws an exception.

              + * + *
              Validate.inclusiveBetween(0, 2, 1);
              + * + * @param the type of the argument object + * @param start the inclusive start value, not null + * @param end the inclusive end value, not null + * @param value the object to validate, not null + * @throws IllegalArgumentException if the value falls outside the boundaries + * @see #inclusiveBetween(Object, Object, Comparable, String, Object...) + * + * @since 3.0 + */ + public static void inclusiveBetween(final T start, final T end, final Comparable value) { + if (value.compareTo(start) < 0 || value.compareTo(end) > 0) { + throw new IllegalArgumentException(String.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); + } + } + + /** + *

              Validate that the specified argument object fall between the two + * inclusive values specified; otherwise, throws an exception with the + * specified message.

              + * + *
              Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");
              + * + * @param the type of the argument object + * @param start the inclusive start value, not null + * @param end the inclusive end value, not null + * @param value the object to validate, not null + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalArgumentException if the value falls outside the boundaries + * @see #inclusiveBetween(Object, Object, Comparable) + * + * @since 3.0 + */ + public static void inclusiveBetween(final T start, final T end, final Comparable value, final String message, final Object... values) { + if (value.compareTo(start) < 0 || value.compareTo(end) > 0) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + /** + * Validate that the specified primitive value falls between the two + * inclusive values specified; otherwise, throws an exception. + * + *
              Validate.inclusiveBetween(0, 2, 1);
              + * + * @param start the inclusive start value + * @param end the inclusive end value + * @param value the value to validate + * @throws IllegalArgumentException if the value falls outside the boundaries (inclusive) + * + * @since 3.3 + */ + public static void inclusiveBetween(final long start, final long end, final long value) { + if (value < start || value > end) { + throw new IllegalArgumentException(String.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); + } + } + + /** + * Validate that the specified primitive value falls between the two + * inclusive values specified; otherwise, throws an exception with the + * specified message. + * + *
              Validate.inclusiveBetween(0, 2, 1, "Not in range");
              + * + * @param start the inclusive start value + * @param end the inclusive end value + * @param value the value to validate + * @param message the exception message if invalid, not null + * + * @throws IllegalArgumentException if the value falls outside the boundaries + * + * @since 3.3 + */ + public static void inclusiveBetween(final long start, final long end, final long value, final String message) { + if (value < start || value > end) { + throw new IllegalArgumentException(message); + } + } + + /** + * Validate that the specified primitive value falls between the two + * inclusive values specified; otherwise, throws an exception. + * + *
              Validate.inclusiveBetween(0.1, 2.1, 1.1);
              + * + * @param start the inclusive start value + * @param end the inclusive end value + * @param value the value to validate + * @throws IllegalArgumentException if the value falls outside the boundaries (inclusive) + * + * @since 3.3 + */ + public static void inclusiveBetween(final double start, final double end, final double value) { + if (value < start || value > end) { + throw new IllegalArgumentException(String.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); + } + } + + /** + * Validate that the specified primitive value falls between the two + * inclusive values specified; otherwise, throws an exception with the + * specified message. + * + *
              Validate.inclusiveBetween(0.1, 2.1, 1.1, "Not in range");
              + * + * @param start the inclusive start value + * @param end the inclusive end value + * @param value the value to validate + * @param message the exception message if invalid, not null + * + * @throws IllegalArgumentException if the value falls outside the boundaries + * + * @since 3.3 + */ + public static void inclusiveBetween(final double start, final double end, final double value, final String message) { + if (value < start || value > end) { + throw new IllegalArgumentException(message); + } + } + + // exclusiveBetween + //--------------------------------------------------------------------------------- + + /** + *

              Validate that the specified argument object fall between the two + * exclusive values specified; otherwise, throws an exception.

              + * + *
              Validate.exclusiveBetween(0, 2, 1);
              + * + * @param the type of the argument object + * @param start the exclusive start value, not null + * @param end the exclusive end value, not null + * @param value the object to validate, not null + * @throws IllegalArgumentException if the value falls outside the boundaries + * @see #exclusiveBetween(Object, Object, Comparable, String, Object...) + * + * @since 3.0 + */ + public static void exclusiveBetween(final T start, final T end, final Comparable value) { + if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) { + throw new IllegalArgumentException(String.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); + } + } + + /** + *

              Validate that the specified argument object fall between the two + * exclusive values specified; otherwise, throws an exception with the + * specified message.

              + * + *
              Validate.exclusiveBetween(0, 2, 1, "Not in boundaries");
              + * + * @param the type of the argument object + * @param start the exclusive start value, not null + * @param end the exclusive end value, not null + * @param value the object to validate, not null + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalArgumentException if the value falls outside the boundaries + * @see #exclusiveBetween(Object, Object, Comparable) + * + * @since 3.0 + */ + public static void exclusiveBetween(final T start, final T end, final Comparable value, final String message, final Object... values) { + if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + /** + * Validate that the specified primitive value falls between the two + * exclusive values specified; otherwise, throws an exception. + * + *
              Validate.exclusiveBetween(0, 2, 1);
              + * + * @param start the exclusive start value + * @param end the exclusive end value + * @param value the value to validate + * @throws IllegalArgumentException if the value falls out of the boundaries + * + * @since 3.3 + */ + public static void exclusiveBetween(final long start, final long end, final long value) { + if (value <= start || value >= end) { + throw new IllegalArgumentException(String.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); + } + } + + /** + * Validate that the specified primitive value falls between the two + * exclusive values specified; otherwise, throws an exception with the + * specified message. + * + *
              Validate.exclusiveBetween(0, 2, 1, "Not in range");
              + * + * @param start the exclusive start value + * @param end the exclusive end value + * @param value the value to validate + * @param message the exception message if invalid, not null + * + * @throws IllegalArgumentException if the value falls outside the boundaries + * + * @since 3.3 + */ + public static void exclusiveBetween(final long start, final long end, final long value, final String message) { + if (value <= start || value >= end) { + throw new IllegalArgumentException(message); + } + } + + /** + * Validate that the specified primitive value falls between the two + * exclusive values specified; otherwise, throws an exception. + * + *
              Validate.exclusiveBetween(0.1, 2.1, 1.1);
              + * + * @param start the exclusive start value + * @param end the exclusive end value + * @param value the value to validate + * @throws IllegalArgumentException if the value falls out of the boundaries + * + * @since 3.3 + */ + public static void exclusiveBetween(final double start, final double end, final double value) { + if (value <= start || value >= end) { + throw new IllegalArgumentException(String.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end)); + } + } + + /** + * Validate that the specified primitive value falls between the two + * exclusive values specified; otherwise, throws an exception with the + * specified message. + * + *
              Validate.exclusiveBetween(0.1, 2.1, 1.1, "Not in range");
              + * + * @param start the exclusive start value + * @param end the exclusive end value + * @param value the value to validate + * @param message the exception message if invalid, not null + * + * @throws IllegalArgumentException if the value falls outside the boundaries + * + * @since 3.3 + */ + public static void exclusiveBetween(final double start, final double end, final double value, final String message) { + if (value <= start || value >= end) { + throw new IllegalArgumentException(message); + } + } + + // isInstanceOf + //--------------------------------------------------------------------------------- + + /** + * Validates that the argument is an instance of the specified class, if not throws an exception. + * + *

              This method is useful when validating according to an arbitrary class

              + * + *
              Validate.isInstanceOf(OkClass.class, object);
              + * + *

              The message of the exception is "Expected type: {type}, actual: {obj_type}"

              + * + * @param type the class the object must be validated against, not null + * @param obj the object to check, null throws an exception + * @throws IllegalArgumentException if argument is not of specified class + * @see #isInstanceOf(Class, Object, String, Object...) + * + * @since 3.0 + */ + public static void isInstanceOf(final Class type, final Object obj) { + if (type.isInstance(obj) == false) { + throw new IllegalArgumentException(String.format(DEFAULT_IS_INSTANCE_OF_EX_MESSAGE, type.getName(), + obj == null ? "null" : obj.getClass().getName())); + } + } + + /** + *

              Validate that the argument is an instance of the specified class; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary class

              + * + *
              Validate.isInstanceOf(OkClass.class, object, "Wrong class, object is of class %s",
              +     *   object.getClass().getName());
              + * + * @param type the class the object must be validated against, not null + * @param obj the object to check, null throws an exception + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalArgumentException if argument is not of specified class + * @see #isInstanceOf(Class, Object) + * + * @since 3.0 + */ + public static void isInstanceOf(final Class type, final Object obj, final String message, final Object... values) { + if (type.isInstance(obj) == false) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + // isAssignableFrom + //--------------------------------------------------------------------------------- + + /** + * Validates that the argument can be converted to the specified class, if not, throws an exception. + * + *

              This method is useful when validating that there will be no casting errors.

              + * + *
              Validate.isAssignableFrom(SuperClass.class, object.getClass());
              + * + *

              The message format of the exception is "Cannot assign {type} to {superType}"

              + * + * @param superType the class the class must be validated against, not null + * @param type the class to check, not null + * @throws IllegalArgumentException if type argument is not assignable to the specified superType + * @see #isAssignableFrom(Class, Class, String, Object...) + * + * @since 3.0 + */ + public static void isAssignableFrom(final Class superType, final Class type) { + if (superType.isAssignableFrom(type) == false) { + throw new IllegalArgumentException(String.format(DEFAULT_IS_ASSIGNABLE_EX_MESSAGE, type == null ? "null" : type.getName(), + superType.getName())); + } + } + + /** + * Validates that the argument can be converted to the specified class, if not throws an exception. + * + *

              This method is useful when validating if there will be no casting errors.

              + * + *
              Validate.isAssignableFrom(SuperClass.class, object.getClass());
              + * + *

              The message of the exception is "The validated object can not be converted to the" + * followed by the name of the class and "class"

              + * + * @param superType the class the class must be validated against, not null + * @param type the class to check, not null + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalArgumentException if argument can not be converted to the specified class + * @see #isAssignableFrom(Class, Class) + */ + public static void isAssignableFrom(final Class superType, final Class type, final String message, final Object... values) { + if (superType.isAssignableFrom(type) == false) { + throw new IllegalArgumentException(String.format(message, values)); + } + } +} diff --git a/src/org/apache/commons/lang3/arch/Processor.java b/src/org/apache/commons/lang3/arch/Processor.java new file mode 100644 index 0000000..1d03a83 --- /dev/null +++ b/src/org/apache/commons/lang3/arch/Processor.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.arch; + +/** + * The {@link Processor} represents a microprocessor and defines + * some properties like architecture and type of the microprocessor. + * @since 3.6 + */ +public class Processor { + + /** + * The {@link Arch} enum defines the architecture of + * a microprocessor. The architecture represents the bit value + * of the microprocessor. + * The following architectures are defined: + *
                + *
              • 32 bit
              • + *
              • 64 bit
              • + *
              • unknown
              • + *
              + */ + public enum Arch { + BIT_32, BIT_64, UNKNOWN + } + + /** + * The {@link Type} enum defines types of a microprocessor. + * The following types are defined: + *
                + *
              • x86
              • + *
              • ia64
              • + *
              • ppc
              • + *
              • unknown
              • + *
              + */ + public enum Type { + X86, IA_64, PPC, UNKNOWN + } + + private final Arch arch; + private final Type type; + + /** + * Constructs a {@link Processor}object with the given + * parameters. + * + * @param arch The processor architecture. + * @param type The processor type. + */ + public Processor(Arch arch, Type type) { + this.arch = arch; + this.type = type; + } + + /** + * Returns the processor architecture as an {@link Arch} enum. + * The processor architecture defines, if the processor has + * a 32 or 64 bit architecture. + * + * @return A {@link Arch} enum. + */ + public Arch getArch() { + return arch; + } + + /** + * Returns the processor type as {@link Type} enum. + * The processor type defines, if the processor is for example + * a x86 or PPA. + * + * @return A {@link Type} enum. + */ + public Type getType() { + return type; + } + + /** + * Checks if {@link Processor} is 32 bit. + * + * @return true, if {@link Processor} is {@link Arch#BIT_32}, else false. + */ + public boolean is32Bit() { + return Arch.BIT_32.equals(arch); + } + + /** + * Checks if {@link Processor} is 64 bit. + * + * @return true, if {@link Processor} is {@link Arch#BIT_64}, else false. + */ + public boolean is64Bit() { + return Arch.BIT_64.equals(arch); + } + + /** + * Checks if {@link Processor} is type of x86. + * + * @return true, if {@link Processor} is {@link Type#X86}, else false. + */ + public boolean isX86() { + return Type.X86.equals(type); + } + + /** + * Checks if {@link Processor} is type of Intel Itanium. + * + * @return true. if {@link Processor} is {@link Type#IA_64}, else false. + */ + public boolean isIA64() { + return Type.IA_64.equals(type); + } + + /** + * Checks if {@link Processor} is type of Power PC. + * + * @return true. if {@link Processor} is {@link Type#PPC}, else false. + */ + public boolean isPPC() { + return Type.PPC.equals(type); + } + +} diff --git a/src/org/apache/commons/lang3/arch/package-info.java b/src/org/apache/commons/lang3/arch/package-info.java new file mode 100644 index 0000000..0a60a81 --- /dev/null +++ b/src/org/apache/commons/lang3/arch/package-info.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Provides classes to work with the values of the os.arch system property. + * @since 3.6 + */ +package org.apache.commons.lang3.arch; \ No newline at end of file diff --git a/src/org/apache/commons/lang3/builder/Builder.java b/src/org/apache/commons/lang3/builder/Builder.java new file mode 100644 index 0000000..496d224 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/Builder.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +/** + *

              + * The Builder interface is designed to designate a class as a builder + * object in the Builder design pattern. Builders are capable of creating and + * configuring objects or results that normally take multiple steps to construct + * or are very complex to derive. + *

              + * + *

              + * The builder interface defines a single method, {@link #build()}, that + * classes must implement. The result of this method should be the final + * configured object or result after all building operations are performed. + *

              + * + *

              + * It is a recommended practice that the methods supplied to configure the + * object or result being built return a reference to {@code this} so that + * method calls can be chained together. + *

              + * + *

              + * Example Builder: + *

              
              + * class FontBuilder implements Builder<Font> {
              + *     private Font font;
              + *     
              + *     public FontBuilder(String fontName) {
              + *         this.font = new Font(fontName, Font.PLAIN, 12);
              + *     }
              + * 
              + *     public FontBuilder bold() {
              + *         this.font = this.font.deriveFont(Font.BOLD);
              + *         return this; // Reference returned so calls can be chained
              + *     }
              + *     
              + *     public FontBuilder size(float pointSize) {
              + *         this.font = this.font.deriveFont(pointSize);
              + *         return this; // Reference returned so calls can be chained
              + *     }
              + * 
              + *     // Other Font construction methods
              + * 
              + *     public Font build() {
              + *         return this.font;
              + *     }
              + * }
              + * 
              + * + * Example Builder Usage: + *
              
              + * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
              + *                                                              .size(14.0f)
              + *                                                              .build();
              + * 
              + * + * + * @param the type of object that the builder will construct or compute. + * + * @since 3.0 + */ +public interface Builder { + + /** + * Returns a reference to the object being constructed or result being + * calculated by the builder. + * + * @return the object constructed or result calculated by the builder. + */ + T build(); +} diff --git a/src/org/apache/commons/lang3/builder/CompareToBuilder.java b/src/org/apache/commons/lang3/builder/CompareToBuilder.java new file mode 100644 index 0000000..875b088 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/CompareToBuilder.java @@ -0,0 +1,1033 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

              It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

              + * + *

              Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

              + * + *

              All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

              + * + *

              To use this class write code as follows:

              + * + *
              + * public class MyClass {
              + *   String field1;
              + *   int field2;
              + *   boolean field3;
              + *
              + *   ...
              + *
              + *   public int compareTo(Object o) {
              + *     MyClass myClass = (MyClass) o;
              + *     return new CompareToBuilder()
              + *       .appendSuper(super.compareTo(o)
              + *       .append(this.field1, myClass.field1)
              + *       .append(this.field2, myClass.field2)
              + *       .append(this.field3, myClass.field3)
              + *       .toComparison();
              + *   }
              + * }
              + * 
              + * + *

              Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

              + * + *

              Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

              + * + *

              A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

              + + *
              + * public int compareTo(Object o) {
              + *   return CompareToBuilder.reflectionCompare(this, o);
              + * }
              + * 
              + * + *

              The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

              + * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

              Constructor for CompareToBuilder.

              + * + *

              Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

              + */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

              Compares two Objects via reflection.

              + * + *

              Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

              + * + *
                + *
              • Static fields will not be compared
              • + *
              • Transient members will be not be compared, as they are likely derived + * fields
              • + *
              • Superclass fields will be compared
              • + *
              + * + *

              If both lhs and rhs are null, + * they are considered equal.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

              Compares two Objects via reflection.

              + * + *

              Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

              + * + *
                + *
              • Static fields will not be compared
              • + *
              • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
              • + *
              • Superclass fields will be compared
              • + *
              + * + *

              If both lhs and rhs are null, + * they are considered equal.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

              Compares two Objects via reflection.

              + * + *

              Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

              + * + *
                + *
              • Static fields will not be compared
              • + *
              • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
              • + *
              • Superclass fields will be compared
              • + *
              + * + *

              If both lhs and rhs are null, + * they are considered equal.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

              Compares two Objects via reflection.

              + * + *

              Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

              + * + *
                + *
              • Static fields will not be compared
              • + *
              • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
              • + *
              • Superclass fields will be compared
              • + *
              + * + *

              If both lhs and rhs are null, + * they are considered equal.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

              Compares two Objects via reflection.

              + * + *

              Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

              + * + *
                + *
              • Static fields will not be compared
              • + *
              • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
              • + *
              • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
              • + *
              + * + *

              If both lhs and rhs are null, + * they are considered equal.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

              Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

              Appends to the builder the compareTo(Object) + * result of the superclass.

              + * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

              Appends to the builder the comparison of + * two Objects.

              + * + *
                + *
              1. Check if lhs == rhs
              2. + *
              3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
              4. + *
              5. Check the object contents
              6. + *
              + * + *

              lhs must either be an array or implement {@link Comparable}.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

              Appends to the builder the comparison of + * two Objects.

              + * + *
                + *
              1. Check if lhs == rhs
              2. + *
              3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
              4. + *
              5. Check the object contents
              6. + *
              + * + *

              If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

              + * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

              Appends to the builder the comparison of + * two doubles.

              + * + *

              This handles NaNs, Infinities, and -0.0.

              + * + *

              It is compatible with the hash code generated by + * HashCodeBuilder.

              + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

              Appends to the builder the comparison of + * two floats.

              + * + *

              This handles NaNs, Infinities, and -0.0.

              + * + *

              It is compatible with the hash code generated by + * HashCodeBuilder.

              + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

              Appends to the builder the deep comparison of + * two Object arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a short length array is less than a long length array
              6. + *
              7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
              8. + *
              + * + *

              This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

              Appends to the builder the deep comparison of + * two Object arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a short length array is less than a long length array
              6. + *
              7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
              8. + *
              + * + *

              This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two long arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(long, long)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two int arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(int, int)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two short arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(short, short)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two char arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(char, char)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two byte arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(byte, byte)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two double arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(double, double)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two float arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(float, float)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Appends to the builder the deep comparison of + * two boolean arrays.

              + * + *
                + *
              1. Check if arrays are the same using ==
              2. + *
              3. Check if for null, null is less than non-null
              4. + *
              5. Check array length, a shorter length array is less than a longer length array
              6. + *
              7. Check array contents element by element using {@link #append(boolean, boolean)}
              8. + *
              + * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/src/org/apache/commons/lang3/builder/Diff.java b/src/org/apache/commons/lang3/builder/Diff.java new file mode 100644 index 0000000..d1b0daf --- /dev/null +++ b/src/org/apache/commons/lang3/builder/Diff.java @@ -0,0 +1,117 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import java.lang.reflect.Type; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.reflect.TypeUtils; +import org.apache.commons.lang3.tuple.Pair; + +/** + *

              + * A {@code Diff} contains the differences between two {@link Diffable} class + * fields. + *

              + * + *

              + * Typically, {@code Diff}s are retrieved by using a {@link DiffBuilder} to + * produce a {@link DiffResult}, containing the differences between two objects. + *

              + * + * + * @param + * The type of object contained within this {@code Diff}. Differences + * between primitive objects are stored as their Object wrapper + * equivalent. + * @since 3.3 + */ +public abstract class Diff extends Pair { + + private static final long serialVersionUID = 1L; + + private final Type type; + private final String fieldName; + + /** + *

              + * Constructs a new {@code Diff} for the given field name. + *

              + * + * @param fieldName + * the name of the field + */ + protected Diff(final String fieldName) { + this.type = ObjectUtils.defaultIfNull( + TypeUtils.getTypeArguments(getClass(), Diff.class).get( + Diff.class.getTypeParameters()[0]), Object.class); + this.fieldName = fieldName; + } + + /** + *

              + * Returns the type of the field. + *

              + * + * @return the field type + */ + public final Type getType() { + return type; + } + + /** + *

              + * Returns the name of the field. + *

              + * + * @return the field name + */ + public final String getFieldName() { + return fieldName; + } + + /** + *

              + * Returns a {@code String} representation of the {@code Diff}, with the + * following format:

              + * + *
              +     * [fieldname: left-value, right-value]
              +     * 
              + * + * + * @return the string representation + */ + @Override + public final String toString() { + return String.format("[%s: %s, %s]", fieldName, getLeft(), getRight()); + } + + /** + *

              + * Throws {@code UnsupportedOperationException}. + *

              + * + * @param value + * ignored + * @return nothing + */ + @Override + public final T setValue(final T value) { + throw new UnsupportedOperationException("Cannot alter Diff object."); + } +} diff --git a/src/org/apache/commons/lang3/builder/DiffBuilder.java b/src/org/apache/commons/lang3/builder/DiffBuilder.java new file mode 100644 index 0000000..bbbcad9 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/DiffBuilder.java @@ -0,0 +1,1022 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; + +/** + *

              + * Assists in implementing {@link Diffable#diff(Object)} methods. + *

              + * + *

              + * To use this class, write code as follows: + *

              + * + *
              + * public class Person implements Diffable<Person> {
              + *   String name;
              + *   int age;
              + *   boolean smoker;
              + *   
              + *   ...
              + *   
              + *   public DiffResult diff(Person obj) {
              + *     // No need for null check, as NullPointerException correct if obj is null
              + *     return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
              + *       .append("name", this.name, obj.name)
              + *       .append("age", this.age, obj.age)
              + *       .append("smoker", this.smoker, obj.smoker)
              + *       .build();
              + *   }
              + * }
              + * 
              + * + *

              + * The {@code ToStringStyle} passed to the constructor is embedded in the + * returned {@code DiffResult} and influences the style of the + * {@code DiffResult.toString()} method. This style choice can be overridden by + * calling {@link DiffResult#toString(ToStringStyle)}. + *

              + * + * @since 3.3 + * @see Diffable + * @see Diff + * @see DiffResult + * @see ToStringStyle + */ +public class DiffBuilder implements Builder { + + private final List> diffs; + private final boolean objectsTriviallyEqual; + private final Object left; + private final Object right; + private final ToStringStyle style; + + /** + *

              + * Constructs a builder for the specified objects with the specified style. + *

              + * + *

              + * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will + * not evaluate any calls to {@code append(...)} and will return an empty + * {@link DiffResult} when {@link #build()} is executed. + *

              + * + * @param lhs + * {@code this} object + * @param rhs + * the object to diff against + * @param style + * the style will use when outputting the objects, {@code null} + * uses the default + * @param testTriviallyEqual + * If true, this will test if lhs and rhs are the same or equal. + * All of the append(fieldName, lhs, rhs) methods will abort + * without creating a field {@link Diff} if the trivially equal + * test is enabled and returns true. The result of this test + * is never changed throughout the life of this {@link DiffBuilder}. + * @throws IllegalArgumentException + * if {@code lhs} or {@code rhs} is {@code null} + * @since 3.4 + */ + public DiffBuilder(final Object lhs, final Object rhs, + final ToStringStyle style, final boolean testTriviallyEqual) { + + if (lhs == null) { + throw new IllegalArgumentException("lhs cannot be null"); + } + if (rhs == null) { + throw new IllegalArgumentException("rhs cannot be null"); + } + + this.diffs = new ArrayList<>(); + this.left = lhs; + this.right = rhs; + this.style = style; + + // Don't compare any fields if objects equal + this.objectsTriviallyEqual = testTriviallyEqual && (lhs == rhs || lhs.equals(rhs)); + } + + /** + *

              + * Constructs a builder for the specified objects with the specified style. + *

              + * + *

              + * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will + * not evaluate any calls to {@code append(...)} and will return an empty + * {@link DiffResult} when {@link #build()} is executed. + *

              + * + *

              + * This delegates to {@link #DiffBuilder(Object, Object, ToStringStyle, boolean)} + * with the testTriviallyEqual flag enabled. + *

              + * + * @param lhs + * {@code this} object + * @param rhs + * the object to diff against + * @param style + * the style will use when outputting the objects, {@code null} + * uses the default + * @throws IllegalArgumentException + * if {@code lhs} or {@code rhs} is {@code null} + */ + public DiffBuilder(final Object lhs, final Object rhs, + final ToStringStyle style) { + + this(lhs, rhs, style, true); + } + + /** + *

              + * Test if two {@code boolean}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code boolean} + * @param rhs + * the right hand {@code boolean} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final boolean lhs, + final boolean rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (lhs != rhs) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Boolean getLeft() { + return Boolean.valueOf(lhs); + } + + @Override + public Boolean getRight() { + return Boolean.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code boolean[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code boolean[]} + * @param rhs + * the right hand {@code boolean[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final boolean[] lhs, + final boolean[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Boolean[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Boolean[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code byte}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code byte} + * @param rhs + * the right hand {@code byte} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final byte lhs, + final byte rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + if (objectsTriviallyEqual) { + return this; + } + if (lhs != rhs) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Byte getLeft() { + return Byte.valueOf(lhs); + } + + @Override + public Byte getRight() { + return Byte.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code byte[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code byte[]} + * @param rhs + * the right hand {@code byte[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final byte[] lhs, + final byte[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Byte[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Byte[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code char}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code char} + * @param rhs + * the right hand {@code char} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final char lhs, + final char rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (lhs != rhs) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Character getLeft() { + return Character.valueOf(lhs); + } + + @Override + public Character getRight() { + return Character.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code char[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code char[]} + * @param rhs + * the right hand {@code char[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final char[] lhs, + final char[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Character[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Character[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code double}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code double} + * @param rhs + * the right hand {@code double} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final double lhs, + final double rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (Double.doubleToLongBits(lhs) != Double.doubleToLongBits(rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Double getLeft() { + return Double.valueOf(lhs); + } + + @Override + public Double getRight() { + return Double.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code double[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code double[]} + * @param rhs + * the right hand {@code double[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final double[] lhs, + final double[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Double[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Double[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code float}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code float} + * @param rhs + * the right hand {@code float} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final float lhs, + final float rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (Float.floatToIntBits(lhs) != Float.floatToIntBits(rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Float getLeft() { + return Float.valueOf(lhs); + } + + @Override + public Float getRight() { + return Float.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code float[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code float[]} + * @param rhs + * the right hand {@code float[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final float[] lhs, + final float[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Float[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Float[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code int}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code int} + * @param rhs + * the right hand {@code int} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final int lhs, + final int rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (lhs != rhs) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Integer getLeft() { + return Integer.valueOf(lhs); + } + + @Override + public Integer getRight() { + return Integer.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code int[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code int[]} + * @param rhs + * the right hand {@code int[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final int[] lhs, + final int[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Integer[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Integer[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code long}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code long} + * @param rhs + * the right hand {@code long} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final long lhs, + final long rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (lhs != rhs) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Long getLeft() { + return Long.valueOf(lhs); + } + + @Override + public Long getRight() { + return Long.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code long[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code long[]} + * @param rhs + * the right hand {@code long[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final long[] lhs, + final long[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Long[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Long[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code short}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code short} + * @param rhs + * the right hand {@code short} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final short lhs, + final short rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (lhs != rhs) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Short getLeft() { + return Short.valueOf(lhs); + } + + @Override + public Short getRight() { + return Short.valueOf(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code short[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code short[]} + * @param rhs + * the right hand {@code short[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final short[] lhs, + final short[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + + if (objectsTriviallyEqual) { + return this; + } + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Short[] getLeft() { + return ArrayUtils.toObject(lhs); + } + + @Override + public Short[] getRight() { + return ArrayUtils.toObject(rhs); + } + }); + } + return this; + } + + /** + *

              + * Test if two {@code Objects}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code Object} + * @param rhs + * the right hand {@code Object} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final Object lhs, + final Object rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + if (objectsTriviallyEqual) { + return this; + } + if (lhs == rhs) { + return this; + } + + Object objectToTest; + if (lhs != null) { + objectToTest = lhs; + } else { + // rhs cannot be null, as lhs != rhs + objectToTest = rhs; + } + + if (objectToTest.getClass().isArray()) { + if (objectToTest instanceof boolean[]) { + return append(fieldName, (boolean[]) lhs, (boolean[]) rhs); + } + if (objectToTest instanceof byte[]) { + return append(fieldName, (byte[]) lhs, (byte[]) rhs); + } + if (objectToTest instanceof char[]) { + return append(fieldName, (char[]) lhs, (char[]) rhs); + } + if (objectToTest instanceof double[]) { + return append(fieldName, (double[]) lhs, (double[]) rhs); + } + if (objectToTest instanceof float[]) { + return append(fieldName, (float[]) lhs, (float[]) rhs); + } + if (objectToTest instanceof int[]) { + return append(fieldName, (int[]) lhs, (int[]) rhs); + } + if (objectToTest instanceof long[]) { + return append(fieldName, (long[]) lhs, (long[]) rhs); + } + if (objectToTest instanceof short[]) { + return append(fieldName, (short[]) lhs, (short[]) rhs); + } + + return append(fieldName, (Object[]) lhs, (Object[]) rhs); + } + + // Not array type + if (lhs != null && lhs.equals(rhs)) { + return this; + } + + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Object getLeft() { + return lhs; + } + + @Override + public Object getRight() { + return rhs; + } + }); + + return this; + } + + /** + *

              + * Test if two {@code Object[]}s are equal. + *

              + * + * @param fieldName + * the field name + * @param lhs + * the left hand {@code Object[]} + * @param rhs + * the right hand {@code Object[]} + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + */ + public DiffBuilder append(final String fieldName, final Object[] lhs, + final Object[] rhs) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + if (objectsTriviallyEqual) { + return this; + } + + if (!Arrays.equals(lhs, rhs)) { + diffs.add(new Diff(fieldName) { + private static final long serialVersionUID = 1L; + + @Override + public Object[] getLeft() { + return lhs; + } + + @Override + public Object[] getRight() { + return rhs; + } + }); + } + + return this; + } + + /** + *

              + * Append diffs from another {@code DiffResult}. + *

              + * + *

              + * This method is useful if you want to compare properties which are + * themselves Diffable and would like to know which specific part of + * it is different. + *

              + * + *
              +     * public class Person implements Diffable<Person> {
              +     *   String name;
              +     *   Address address; // implements Diffable<Address>
              +     *   
              +     *   ...
              +     *   
              +     *   public DiffResult diff(Person obj) {
              +     *     return new DiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
              +     *       .append("name", this.name, obj.name)
              +     *       .append("address", this.address.diff(obj.address))
              +     *       .build();
              +     *   }
              +     * }
              +     * 
              + * + * @param fieldName + * the field name + * @param diffResult + * the {@code DiffResult} to append + * @return this + * @throws IllegalArgumentException + * if field name is {@code null} + * @since 3.5 + */ + public DiffBuilder append(final String fieldName, + final DiffResult diffResult) { + if (fieldName == null) { + throw new IllegalArgumentException("Field name cannot be null"); + } + if (diffResult == null) { + throw new IllegalArgumentException("Diff result cannot be null"); + } + if (objectsTriviallyEqual) { + return this; + } + + for (final Diff diff : diffResult.getDiffs()) { + append(fieldName + "." + diff.getFieldName(), + diff.getLeft(), diff.getRight()); + } + + return this; + } + + /** + *

              + * Builds a {@link DiffResult} based on the differences appended to this + * builder. + *

              + * + * @return a {@code DiffResult} containing the differences between the two + * objects. + */ + @Override + public DiffResult build() { + return new DiffResult(left, right, diffs, style); + } + +} diff --git a/src/org/apache/commons/lang3/builder/DiffResult.java b/src/org/apache/commons/lang3/builder/DiffResult.java new file mode 100644 index 0000000..2dbd85e --- /dev/null +++ b/src/org/apache/commons/lang3/builder/DiffResult.java @@ -0,0 +1,207 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +/** + *

              + * A {@code DiffResult} contains a collection of the differences between two + * {@link Diffable} objects. Typically these differences are displayed using + * {@link #toString()} method, which returns a string describing the fields that + * differ between the objects. + *

              + *

              + * Use a {@link DiffBuilder} to build a {@code DiffResult} comparing two objects. + *

              + * + * @since 3.3 + */ +public class DiffResult implements Iterable> { + + /** + *

              + * The {@code String} returned when the objects have no differences: + * {@value} + *

              + */ + public static final String OBJECTS_SAME_STRING = ""; + + private static final String DIFFERS_STRING = "differs from"; + + private final List> diffs; + private final Object lhs; + private final Object rhs; + private final ToStringStyle style; + + /** + *

              + * Creates a {@link DiffResult} containing the differences between two + * objects. + *

              + * + * @param lhs + * the left hand object + * @param rhs + * the right hand object + * @param diffs + * the list of differences, may be empty + * @param style + * the style to use for the {@link #toString()} method. May be + * {@code null}, in which case + * {@link ToStringStyle#DEFAULT_STYLE} is used + * @throws IllegalArgumentException + * if {@code lhs}, {@code rhs} or {@code diffs} is {@code null} + */ + DiffResult(final Object lhs, final Object rhs, final List> diffs, + final ToStringStyle style) { + if (lhs == null) { + throw new IllegalArgumentException( + "Left hand object cannot be null"); + } + if (rhs == null) { + throw new IllegalArgumentException( + "Right hand object cannot be null"); + } + if (diffs == null) { + throw new IllegalArgumentException( + "List of differences cannot be null"); + } + + this.diffs = diffs; + this.lhs = lhs; + this.rhs = rhs; + + if (style == null) { + this.style = ToStringStyle.DEFAULT_STYLE; + } else { + this.style = style; + } + } + + /** + *

              + * Returns an unmodifiable list of {@code Diff}s. The list may be empty if + * there were no differences between the objects. + *

              + * + * @return an unmodifiable list of {@code Diff}s + */ + public List> getDiffs() { + return Collections.unmodifiableList(diffs); + } + + /** + *

              + * Returns the number of differences between the two objects. + *

              + * + * @return the number of differences + */ + public int getNumberOfDiffs() { + return diffs.size(); + } + + /** + *

              + * Returns the style used by the {@link #toString()} method. + *

              + * + * @return the style + */ + public ToStringStyle getToStringStyle() { + return style; + } + + /** + *

              + * Builds a {@code String} description of the differences contained within + * this {@code DiffResult}. A {@link ToStringBuilder} is used for each object + * and the style of the output is governed by the {@code ToStringStyle} + * passed to the constructor. + *

              + * + *

              + * If there are no differences stored in this list, the method will return + * {@link #OBJECTS_SAME_STRING}. Otherwise, using the example given in + * {@link Diffable} and {@link ToStringStyle#SHORT_PREFIX_STYLE}, an output + * might be: + *

              + * + *
              +     * Person[name=John Doe,age=32] differs from Person[name=Joe Bloggs,age=26]
              +     * 
              + * + *

              + * This indicates that the objects differ in name and age, but not in + * smoking status. + *

              + * + *

              + * To use a different {@code ToStringStyle} for an instance of this class, + * use {@link #toString(ToStringStyle)}. + *

              + * + * @return a {@code String} description of the differences. + */ + @Override + public String toString() { + return toString(style); + } + + /** + *

              + * Builds a {@code String} description of the differences contained within + * this {@code DiffResult}, using the supplied {@code ToStringStyle}. + *

              + * + * @param style + * the {@code ToStringStyle} to use when outputting the objects + * + * @return a {@code String} description of the differences. + */ + public String toString(final ToStringStyle style) { + if (diffs.size() == 0) { + return OBJECTS_SAME_STRING; + } + + final ToStringBuilder lhsBuilder = new ToStringBuilder(lhs, style); + final ToStringBuilder rhsBuilder = new ToStringBuilder(rhs, style); + + for (final Diff diff : diffs) { + lhsBuilder.append(diff.getFieldName(), diff.getLeft()); + rhsBuilder.append(diff.getFieldName(), diff.getRight()); + } + + return String.format("%s %s %s", lhsBuilder.build(), DIFFERS_STRING, + rhsBuilder.build()); + } + + /** + *

              + * Returns an iterator over the {@code Diff} objects contained in this list. + *

              + * + * @return the iterator + */ + @Override + public Iterator> iterator() { + return diffs.iterator(); + } +} diff --git a/src/org/apache/commons/lang3/builder/Diffable.java b/src/org/apache/commons/lang3/builder/Diffable.java new file mode 100644 index 0000000..9f85eb1 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/Diffable.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +/** + *

              {@code Diffable} classes can be compared with other objects + * for differences. The {@link DiffResult} object retrieved can be queried + * for a list of differences or printed using the {@link DiffResult#toString()}.

              + * + *

              The calculation of the differences is consistent with equals if + * and only if {@code d1.equals(d2)} implies {@code d1.diff(d2) == ""}. + * It is strongly recommended that implementations are consistent with equals + * to avoid confusion. Note that {@code null} is not an instance of any class + * and {@code d1.diff(null)} should throw a {@code NullPointerException}.

              + * + *

              + * {@code Diffable} classes lend themselves well to unit testing, in which a + * easily readable description of the differences between an anticipated result and + * an actual result can be retrieved. For example: + *

              + *
              + * Assert.assertEquals(expected.diff(result), expected, result);
              + * 
              + * + * @param the type of objects that this object may be differentiated against + * @since 3.3 + */ +public interface Diffable { + + /** + *

              Retrieves a list of the differences between + * this object and the supplied object.

              + * + * @param obj the object to diff against, can be {@code null} + * @return a list of differences + * @throws NullPointerException if the specified object is {@code null} + */ + DiffResult diff(T obj); +} diff --git a/src/org/apache/commons/lang3/builder/EqualsBuilder.java b/src/org/apache/commons/lang3/builder/EqualsBuilder.java new file mode 100644 index 0000000..aa7fb06 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/EqualsBuilder.java @@ -0,0 +1,1115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.tuple.Pair; + +/** + *

              Assists in implementing {@link Object#equals(Object)} methods.

              + * + *

              This class provides methods to build a good equals method for any + * class. It follows rules laid out in + * Effective Java + * , by Joshua Bloch. In particular the rule for comparing doubles, + * floats, and arrays can be tricky. Also, making sure that + * equals() and hashCode() are consistent can be + * difficult.

              + * + *

              Two Objects that compare as equals must generate the same hash code, + * but two Objects with the same hash code do not have to be equal.

              + * + *

              All relevant fields should be included in the calculation of equals. + * Derived fields may be ignored. In particular, any field used in + * generating a hash code must be used in the equals method, and vice + * versa.

              + * + *

              Typical use for the code is as follows:

              + *
              + * public boolean equals(Object obj) {
              + *   if (obj == null) { return false; }
              + *   if (obj == this) { return true; }
              + *   if (obj.getClass() != getClass()) {
              + *     return false;
              + *   }
              + *   MyClass rhs = (MyClass) obj;
              + *   return new EqualsBuilder()
              + *                 .appendSuper(super.equals(obj))
              + *                 .append(field1, rhs.field1)
              + *                 .append(field2, rhs.field2)
              + *                 .append(field3, rhs.field3)
              + *                 .isEquals();
              + *  }
              + * 
              + * + *

              Alternatively, there is a method that uses reflection to determine + * the fields to test. Because these fields are usually private, the method, + * reflectionEquals, uses AccessibleObject.setAccessible to + * change the visibility of the fields. This will fail under a security + * manager, unless the appropriate permissions are set up correctly. It is + * also slower than testing explicitly. Non-primitive fields are compared using + * equals().

              + * + *

              A typical invocation for this method would look like:

              + *
              + * public boolean equals(Object obj) {
              + *   return EqualsBuilder.reflectionEquals(this, obj);
              + * }
              + * 
              + * + *

              The {@link EqualsExclude} annotation can be used to exclude fields from being + * used by the reflectionEquals methods.

              + * + * @since 1.0 + */ +public class EqualsBuilder implements Builder { + + /** + *

              + * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops. + *

              + * + * @since 3.0 + */ + private static final ThreadLocal>> REGISTRY = new ThreadLocal<>(); + + /* + * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode() + * we are in the process of calculating. + * + * So we generate a one-to-one mapping from the original object to a new object. + * + * Now HashSet uses equals() to determine if two elements with the same hash code really + * are equal, so we also need to ensure that the replacement objects are only equal + * if the original objects are identical. + * + * The original implementation (2.4 and before) used the System.identityHashCode() + * method - however this is not guaranteed to generate unique ids (e.g. LANG-459) + * + * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey) + * to disambiguate the duplicate ids. + */ + + /** + *

              + * Returns the registry of object pairs being traversed by the reflection + * methods in the current thread. + *

              + * + * @return Set the registry of objects being traversed + * @since 3.0 + */ + static Set> getRegistry() { + return REGISTRY.get(); + } + + /** + *

              + * Converters value pair into a register pair. + *

              + * + * @param lhs this object + * @param rhs the other object + * + * @return the pair + */ + static Pair getRegisterPair(final Object lhs, final Object rhs) { + final IDKey left = new IDKey(lhs); + final IDKey right = new IDKey(rhs); + return Pair.of(left, right); + } + + /** + *

              + * Returns true if the registry contains the given object pair. + * Used by the reflection methods to avoid infinite loops. + * Objects might be swapped therefore a check is needed if the object pair + * is registered in given or swapped order. + *

              + * + * @param lhs this object to lookup in registry + * @param rhs the other object to lookup on registry + * @return boolean true if the registry contains the given object. + * @since 3.0 + */ + static boolean isRegistered(final Object lhs, final Object rhs) { + final Set> registry = getRegistry(); + final Pair pair = getRegisterPair(lhs, rhs); + final Pair swappedPair = Pair.of(pair.getLeft(), pair.getRight()); + + return registry != null + && (registry.contains(pair) || registry.contains(swappedPair)); + } + + /** + *

              + * Registers the given object pair. + * Used by the reflection methods to avoid infinite loops. + *

              + * + * @param lhs this object to register + * @param rhs the other object to register + */ + private static void register(final Object lhs, final Object rhs) { + Set> registry = getRegistry(); + if (registry == null) { + registry = new HashSet<>(); + REGISTRY.set(registry); + } + final Pair pair = getRegisterPair(lhs, rhs); + registry.add(pair); + } + + /** + *

              + * Unregisters the given object pair. + *

              + * + *

              + * Used by the reflection methods to avoid infinite loops. + * + * @param lhs this object to unregister + * @param rhs the other object to unregister + * @since 3.0 + */ + private static void unregister(final Object lhs, final Object rhs) { + final Set> registry = getRegistry(); + if (registry != null) { + final Pair pair = getRegisterPair(lhs, rhs); + registry.remove(pair); + if (registry.isEmpty()) { + REGISTRY.remove(); + } + } + } + + /** + * If the fields tested are equals. + * The default value is true. + */ + private boolean isEquals = true; + + private boolean testTransients = false; + private boolean testRecursive = false; + private Class reflectUpToClass = null; + private String[] excludeFields = null; + + /** + *

              Constructor for EqualsBuilder.

              + * + *

              Starts off assuming that equals is true.

              + * @see Object#equals(Object) + */ + public EqualsBuilder() { + // do nothing for now. + } + + //------------------------------------------------------------------------- + + /** + * Set whether to include transient fields when reflectively comparing objects. + * @param testTransients whether to test transient fields + * @return EqualsBuilder - used to chain calls. + * @since 3.6 + */ + public EqualsBuilder setTestTransients(final boolean testTransients) { + this.testTransients = testTransients; + return this; + } + + /** + * Set whether to include transient fields when reflectively comparing objects. + * @param testRecursive whether to do a recursive test + * @return EqualsBuilder - used to chain calls. + * @since 3.6 + */ + public EqualsBuilder setTestRecursive(final boolean testRecursive) { + this.testRecursive = testRecursive; + return this; + } + + /** + * Set the superclass to reflect up to at reflective tests. + * @param reflectUpToClass the super class to reflect up to + * @return EqualsBuilder - used to chain calls. + * @since 3.6 + */ + public EqualsBuilder setReflectUpToClass(final Class reflectUpToClass) { + this.reflectUpToClass = reflectUpToClass; + return this; + } + + /** + * Set field names to be excluded by reflection tests. + * @param excludeFields the fields to exclude + * @return EqualsBuilder - used to chain calls. + * @since 3.6 + */ + public EqualsBuilder setExcludeFields(final String... excludeFields) { + this.excludeFields = excludeFields; + return this; + } + + + /** + *

              This method uses reflection to determine if the two Objects + * are equal.

              + * + *

              It uses AccessibleObject.setAccessible to gain access to private + * fields. This means that it will throw a security exception if run under + * a security manager, if the permissions are not set up correctly. It is also + * not as efficient as testing explicitly. Non-primitive fields are compared using + * equals().

              + * + *

              Transient members will be not be tested, as they are likely derived + * fields, and not part of the value of the Object.

              + * + *

              Static fields will not be tested. Superclass fields will be included.

              + * + * @param lhs this object + * @param rhs the other object + * @param excludeFields Collection of String field names to exclude from testing + * @return true if the two Objects have tested equals. + * + * @see EqualsExclude + */ + public static boolean reflectionEquals(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

              This method uses reflection to determine if the two Objects + * are equal.

              + * + *

              It uses AccessibleObject.setAccessible to gain access to private + * fields. This means that it will throw a security exception if run under + * a security manager, if the permissions are not set up correctly. It is also + * not as efficient as testing explicitly. Non-primitive fields are compared using + * equals().

              + * + *

              Transient members will be not be tested, as they are likely derived + * fields, and not part of the value of the Object.

              + * + *

              Static fields will not be tested. Superclass fields will be included.

              + * + * @param lhs this object + * @param rhs the other object + * @param excludeFields array of field names to exclude from testing + * @return true if the two Objects have tested equals. + * + * @see EqualsExclude + */ + public static boolean reflectionEquals(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionEquals(lhs, rhs, false, null, excludeFields); + } + + /** + *

              This method uses reflection to determine if the two Objects + * are equal.

              + * + *

              It uses AccessibleObject.setAccessible to gain access to private + * fields. This means that it will throw a security exception if run under + * a security manager, if the permissions are not set up correctly. It is also + * not as efficient as testing explicitly. Non-primitive fields are compared using + * equals().

              + * + *

              If the TestTransients parameter is set to true, transient + * members will be tested, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object.

              + * + *

              Static fields will not be tested. Superclass fields will be included.

              + * + * @param lhs this object + * @param rhs the other object + * @param testTransients whether to include transient fields + * @return true if the two Objects have tested equals. + * + * @see EqualsExclude + */ + public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients) { + return reflectionEquals(lhs, rhs, testTransients, null); + } + + /** + *

              This method uses reflection to determine if the two Objects + * are equal.

              + * + *

              It uses AccessibleObject.setAccessible to gain access to private + * fields. This means that it will throw a security exception if run under + * a security manager, if the permissions are not set up correctly. It is also + * not as efficient as testing explicitly. Non-primitive fields are compared using + * equals().

              + * + *

              If the testTransients parameter is set to true, transient + * members will be tested, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object.

              + * + *

              Static fields will not be included. Superclass fields will be appended + * up to and including the specified superclass. A null superclass is treated + * as java.lang.Object.

              + * + * @param lhs this object + * @param rhs the other object + * @param testTransients whether to include transient fields + * @param reflectUpToClass the superclass to reflect up to (inclusive), + * may be null + * @param excludeFields array of field names to exclude from testing + * @return true if the two Objects have tested equals. + * + * @see EqualsExclude + * @since 2.0 + */ + public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class reflectUpToClass, + final String... excludeFields) { + return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, false, excludeFields); + } + + /** + *

              This method uses reflection to determine if the two Objects + * are equal.

              + * + *

              It uses AccessibleObject.setAccessible to gain access to private + * fields. This means that it will throw a security exception if run under + * a security manager, if the permissions are not set up correctly. It is also + * not as efficient as testing explicitly. Non-primitive fields are compared using + * equals().

              + * + *

              If the testTransients parameter is set to true, transient + * members will be tested, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object.

              + * + *

              Static fields will not be included. Superclass fields will be appended + * up to and including the specified superclass. A null superclass is treated + * as java.lang.Object.

              + * + *

              If the testRecursive parameter is set to true, non primitive + * (and non primitive wrapper) field types will be compared by + * EqualsBuilder recursively instead of invoking their + * equals() method. Leading to a deep reflection equals test. + * + * @param lhs this object + * @param rhs the other object + * @param testTransients whether to include transient fields + * @param reflectUpToClass the superclass to reflect up to (inclusive), + * may be null + * @param testRecursive whether to call reflection equals on non primitive + * fields recursively. + * @param excludeFields array of field names to exclude from testing + * @return true if the two Objects have tested equals. + * + * @see EqualsExclude + * @since 3.6 + */ + public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class reflectUpToClass, + final boolean testRecursive, final String... excludeFields) { + if (lhs == rhs) { + return true; + } + if (lhs == null || rhs == null) { + return false; + } + return new EqualsBuilder() + .setExcludeFields(excludeFields) + .setReflectUpToClass(reflectUpToClass) + .setTestTransients(testTransients) + .setTestRecursive(testRecursive) + .reflectionAppend(lhs, rhs) + .isEquals(); + } + + /** + *

              Tests if two objects by using reflection.

              + * + *

              It uses AccessibleObject.setAccessible to gain access to private + * fields. This means that it will throw a security exception if run under + * a security manager, if the permissions are not set up correctly. It is also + * not as efficient as testing explicitly. Non-primitive fields are compared using + * equals().

              + * + *

              If the testTransients field is set to true, transient + * members will be tested, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object.

              + * + *

              Static fields will not be included. Superclass fields will be appended + * up to and including the specified superclass in field reflectUpToClass. + * A null superclass is treated as java.lang.Object.

              + * + *

              Field names listed in field excludeFields will be ignored.

              + * + * @param lhs the left hand object + * @param rhs the left hand object + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder reflectionAppend(final Object lhs, final Object rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + isEquals = false; + return this; + } + + // Find the leaf class since there may be transients in the leaf + // class or in classes between the leaf and root. + // If we are not testing transients or a subclass has no ivars, + // then a subclass can test equals to a superclass. + final Class lhsClass = lhs.getClass(); + final Class rhsClass = rhs.getClass(); + Class testClass; + if (lhsClass.isInstance(rhs)) { + testClass = lhsClass; + if (!rhsClass.isInstance(lhs)) { + // rhsClass is a subclass of lhsClass + testClass = rhsClass; + } + } else if (rhsClass.isInstance(lhs)) { + testClass = rhsClass; + if (!lhsClass.isInstance(rhs)) { + // lhsClass is a subclass of rhsClass + testClass = lhsClass; + } + } else { + // The two classes are not related. + isEquals = false; + return this; + } + + try { + if (testClass.isArray()) { + append(lhs, rhs); + } else { + reflectionAppend(lhs, rhs, testClass); + while (testClass.getSuperclass() != null && testClass != reflectUpToClass) { + testClass = testClass.getSuperclass(); + reflectionAppend(lhs, rhs, testClass); + } + } + } catch (final IllegalArgumentException e) { + // In this case, we tried to test a subclass vs. a superclass and + // the subclass has ivars or the ivars are transient and + // we are testing transients. + // If a subclass has ivars that we are trying to test them, we get an + // exception and we know that the objects are not equal. + isEquals = false; + return this; + } + return this; + } + + /** + *

              Appends the fields and values defined by the given object of the + * given Class.

              + * + * @param lhs the left hand object + * @param rhs the right hand object + * @param clazz the class to append details of + */ + private void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz) { + + if (isRegistered(lhs, rhs)) { + return; + } + + try { + register(lhs, rhs); + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && isEquals; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (testTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers()) + && !f.isAnnotationPresent(EqualsExclude.class)) { + try { + append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + //this can't happen. Would get a Security exception instead + //throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } finally { + unregister(lhs, rhs); + } + } + + //------------------------------------------------------------------------- + + /** + *

              Adds the result of super.equals() to this builder.

              + * + * @param superEquals the result of calling super.equals() + * @return EqualsBuilder - used to chain calls. + * @since 2.0 + */ + public EqualsBuilder appendSuper(final boolean superEquals) { + if (!isEquals) { + return this; + } + isEquals = superEquals; + return this; + } + + //------------------------------------------------------------------------- + + /** + *

              Test if two Objects are equal using either + * #{@link #reflectionAppend(Object, Object)}, if object are non + * primitives (or wrapper of primitives) or if field testRecursive + * is set to false. Otherwise, using their + * equals method.

              + * + * @param lhs the left hand object + * @param rhs the right hand object + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final Object lhs, final Object rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + final Class lhsClass = lhs.getClass(); + if (!lhsClass.isArray()) { + // The simple case, not an array, just test the element + if (testRecursive && !ClassUtils.isPrimitiveOrWrapper(lhsClass)) { + reflectionAppend(lhs, rhs); + } else { + isEquals = lhs.equals(rhs); + } + } else { + // factor out array case in order to keep method small enough + // to be inlined + appendArray(lhs, rhs); + } + return this; + } + + /** + *

              Test if an Object is equal to an array.

              + * + * @param lhs the left hand object, an array + * @param rhs the right hand object + */ + private void appendArray(final Object lhs, final Object rhs) { + if (lhs.getClass() != rhs.getClass()) { + // Here when we compare different dimensions, for example: a boolean[][] to a boolean[] + this.setEquals(false); + } + // 'Switch' on type of array, to dispatch to the correct handler + // This handles multi dimensional arrays of the same depth + else if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // Not an array of primitives + append((Object[]) lhs, (Object[]) rhs); + } + } + + /** + *

              + * Test if two long s are equal. + *

              + * + * @param lhs + * the left hand long + * @param rhs + * the right hand long + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final long lhs, final long rhs) { + if (!isEquals) { + return this; + } + isEquals = lhs == rhs; + return this; + } + + /** + *

              Test if two ints are equal.

              + * + * @param lhs the left hand int + * @param rhs the right hand int + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final int lhs, final int rhs) { + if (!isEquals) { + return this; + } + isEquals = lhs == rhs; + return this; + } + + /** + *

              Test if two shorts are equal.

              + * + * @param lhs the left hand short + * @param rhs the right hand short + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final short lhs, final short rhs) { + if (!isEquals) { + return this; + } + isEquals = lhs == rhs; + return this; + } + + /** + *

              Test if two chars are equal.

              + * + * @param lhs the left hand char + * @param rhs the right hand char + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final char lhs, final char rhs) { + if (!isEquals) { + return this; + } + isEquals = lhs == rhs; + return this; + } + + /** + *

              Test if two bytes are equal.

              + * + * @param lhs the left hand byte + * @param rhs the right hand byte + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final byte lhs, final byte rhs) { + if (!isEquals) { + return this; + } + isEquals = lhs == rhs; + return this; + } + + /** + *

              Test if two doubles are equal by testing that the + * pattern of bits returned by doubleToLong are equal.

              + * + *

              This handles NaNs, Infinities, and -0.0.

              + * + *

              It is compatible with the hash code generated by + * HashCodeBuilder.

              + * + * @param lhs the left hand double + * @param rhs the right hand double + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final double lhs, final double rhs) { + if (!isEquals) { + return this; + } + return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs)); + } + + /** + *

              Test if two floats are equal byt testing that the + * pattern of bits returned by doubleToLong are equal.

              + * + *

              This handles NaNs, Infinities, and -0.0.

              + * + *

              It is compatible with the hash code generated by + * HashCodeBuilder.

              + * + * @param lhs the left hand float + * @param rhs the right hand float + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final float lhs, final float rhs) { + if (!isEquals) { + return this; + } + return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs)); + } + + /** + *

              Test if two booleanss are equal.

              + * + * @param lhs the left hand boolean + * @param rhs the right hand boolean + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final boolean lhs, final boolean rhs) { + if (!isEquals) { + return this; + } + isEquals = lhs == rhs; + return this; + } + + /** + *

              Performs a deep comparison of two Object arrays.

              + * + *

              This also will be called for the top level of + * multi-dimensional, ragged, and multi-typed arrays.

              + * + *

              Note that this method does not compare the type of the arrays; it only + * compares the contents.

              + * + * @param lhs the left hand Object[] + * @param rhs the right hand Object[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final Object[] lhs, final Object[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of long. Length and all + * values are compared.

              + * + *

              The method {@link #append(long, long)} is used.

              + * + * @param lhs the left hand long[] + * @param rhs the right hand long[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final long[] lhs, final long[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of int. Length and all + * values are compared.

              + * + *

              The method {@link #append(int, int)} is used.

              + * + * @param lhs the left hand int[] + * @param rhs the right hand int[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final int[] lhs, final int[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of short. Length and all + * values are compared.

              + * + *

              The method {@link #append(short, short)} is used.

              + * + * @param lhs the left hand short[] + * @param rhs the right hand short[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final short[] lhs, final short[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of char. Length and all + * values are compared.

              + * + *

              The method {@link #append(char, char)} is used.

              + * + * @param lhs the left hand char[] + * @param rhs the right hand char[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final char[] lhs, final char[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of byte. Length and all + * values are compared.

              + * + *

              The method {@link #append(byte, byte)} is used.

              + * + * @param lhs the left hand byte[] + * @param rhs the right hand byte[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final byte[] lhs, final byte[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of double. Length and all + * values are compared.

              + * + *

              The method {@link #append(double, double)} is used.

              + * + * @param lhs the left hand double[] + * @param rhs the right hand double[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final double[] lhs, final double[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of float. Length and all + * values are compared.

              + * + *

              The method {@link #append(float, float)} is used.

              + * + * @param lhs the left hand float[] + * @param rhs the right hand float[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final float[] lhs, final float[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Deep comparison of array of boolean. Length and all + * values are compared.

              + * + *

              The method {@link #append(boolean, boolean)} is used.

              + * + * @param lhs the left hand boolean[] + * @param rhs the right hand boolean[] + * @return EqualsBuilder - used to chain calls. + */ + public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (!isEquals) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null || rhs == null) { + this.setEquals(false); + return this; + } + if (lhs.length != rhs.length) { + this.setEquals(false); + return this; + } + for (int i = 0; i < lhs.length && isEquals; ++i) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

              Returns true if the fields that have been checked + * are all equal.

              + * + * @return boolean + */ + public boolean isEquals() { + return this.isEquals; + } + + /** + *

              Returns true if the fields that have been checked + * are all equal.

              + * + * @return true if all of the fields that have been checked + * are equal, false otherwise. + * + * @since 3.0 + */ + @Override + public Boolean build() { + return Boolean.valueOf(isEquals()); + } + + /** + * Sets the isEquals value. + * + * @param isEquals The value to set. + * @since 2.1 + */ + protected void setEquals(final boolean isEquals) { + this.isEquals = isEquals; + } + + /** + * Reset the EqualsBuilder so you can use the same object again + * @since 2.5 + */ + public void reset() { + this.isEquals = true; + } +} diff --git a/src/org/apache/commons/lang3/builder/EqualsExclude.java b/src/org/apache/commons/lang3/builder/EqualsExclude.java new file mode 100644 index 0000000..fe09f81 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/EqualsExclude.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.builder; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Use this annotation to exclude a field from being being used by + * the various reflectionEquals methods defined on + * {@link EqualsBuilder}. + * + * @since 3.5 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface EqualsExclude { + +} diff --git a/src/org/apache/commons/lang3/builder/HashCodeBuilder.java b/src/org/apache/commons/lang3/builder/HashCodeBuilder.java new file mode 100644 index 0000000..8511cd7 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/HashCodeBuilder.java @@ -0,0 +1,996 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.Validate; + +/** + *

              + * Assists in implementing {@link Object#hashCode()} methods. + *

              + * + *

              + * This class enables a good hashCode method to be built for any class. It follows the rules laid out in + * the book Effective Java by Joshua Bloch. Writing a + * good hashCode method is actually quite difficult. This class aims to simplify the process. + *

              + * + *

              + * The following is the approach taken. When appending a data field, the current total is multiplied by the + * multiplier then a relevant value + * for that data type is added. For example, if the current hashCode is 17, and the multiplier is 37, then + * appending the integer 45 will create a hash code of 674, namely 17 * 37 + 45. + *

              + * + *

              + * All relevant fields from the object should be included in the hashCode method. Derived fields may be + * excluded. In general, any field used in the equals method must be used in the hashCode + * method. + *

              + * + *

              + * To use this class write code as follows: + *

              + * + *
              + * public class Person {
              + *   String name;
              + *   int age;
              + *   boolean smoker;
              + *   ...
              + *
              + *   public int hashCode() {
              + *     // you pick a hard-coded, randomly chosen, non-zero, odd number
              + *     // ideally different for each class
              + *     return new HashCodeBuilder(17, 37).
              + *       append(name).
              + *       append(age).
              + *       append(smoker).
              + *       toHashCode();
              + *   }
              + * }
              + * 
              + * + *

              + * If required, the superclass hashCode() can be added using {@link #appendSuper}. + *

              + * + *

              + * Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are + * usually private, the method, reflectionHashCode, uses AccessibleObject.setAccessible + * to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions + * are set up correctly. It is also slower than testing explicitly. + *

              + * + *

              + * A typical invocation for this method would look like: + *

              + * + *
              + * public int hashCode() {
              + *   return HashCodeBuilder.reflectionHashCode(this);
              + * }
              + * 
              + * + *

              The {@link HashCodeExclude} annotation can be used to exclude fields from being + * used by the reflectionHashCode methods.

              + * + * @since 1.0 + */ +public class HashCodeBuilder implements Builder { + /** + * The default initial value to use in reflection hash code building. + */ + private static final int DEFAULT_INITIAL_VALUE = 17; + + /** + * The default multiplier value to use in reflection hash code building. + */ + private static final int DEFAULT_MULTIPLIER_VALUE = 37; + + /** + *

              + * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops. + *

              + * + * @since 2.3 + */ + private static final ThreadLocal> REGISTRY = new ThreadLocal<>(); + + /* + * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode() + * we are in the process of calculating. + * + * So we generate a one-to-one mapping from the original object to a new object. + * + * Now HashSet uses equals() to determine if two elements with the same hash code really + * are equal, so we also need to ensure that the replacement objects are only equal + * if the original objects are identical. + * + * The original implementation (2.4 and before) used the System.identityHashCode() + * method - however this is not guaranteed to generate unique ids (e.g. LANG-459) + * + * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey) + * to disambiguate the duplicate ids. + */ + + /** + *

              + * Returns the registry of objects being traversed by the reflection methods in the current thread. + *

              + * + * @return Set the registry of objects being traversed + * @since 2.3 + */ + static Set getRegistry() { + return REGISTRY.get(); + } + + /** + *

              + * Returns true if the registry contains the given object. Used by the reflection methods to avoid + * infinite loops. + *

              + * + * @param value + * The object to lookup in the registry. + * @return boolean true if the registry contains the given object. + * @since 2.3 + */ + static boolean isRegistered(final Object value) { + final Set registry = getRegistry(); + return registry != null && registry.contains(new IDKey(value)); + } + + /** + *

              + * Appends the fields and values defined by the given object of the given Class. + *

              + * + * @param object + * the object to append details of + * @param clazz + * the class to append details of + * @param builder + * the builder to append to + * @param useTransients + * whether to use transient fields + * @param excludeFields + * Collection of String field names to exclude from use in calculation of hash code + */ + private static void reflectionAppend(final Object object, final Class clazz, final HashCodeBuilder builder, final boolean useTransients, + final String[] excludeFields) { + if (isRegistered(object)) { + return; + } + try { + register(object); + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (final Field field : fields) { + if (!ArrayUtils.contains(excludeFields, field.getName()) + && !field.getName().contains("$") + && (useTransients || !Modifier.isTransient(field.getModifiers())) + && !Modifier.isStatic(field.getModifiers()) + && !field.isAnnotationPresent(HashCodeExclude.class)) { + try { + final Object fieldValue = field.get(object); + builder.append(fieldValue); + } catch (final IllegalAccessException e) { + // this can't happen. Would get a Security exception instead + // throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } finally { + unregister(object); + } + } + + /** + *

              + * Uses reflection to build a valid hash code from the fields of {@code object}. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * Transient members will be not be used, as they are likely derived fields, and not part of the value of the + * Object. + *

              + * + *

              + * Static fields will not be tested. Superclass fields will be included. + *

              + * + *

              + * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, + * however this is not vital. Prime numbers are preferred, especially for the multiplier. + *

              + * + * @param initialNonZeroOddNumber + * a non-zero, odd number used as the initial value. This will be the returned + * value if no fields are found to include in the hash code + * @param multiplierNonZeroOddNumber + * a non-zero, odd number used as the multiplier + * @param object + * the Object to create a hashCode for + * @return int hash code + * @throws IllegalArgumentException + * if the Object is null + * @throws IllegalArgumentException + * if the number is zero or even + * + * @see HashCodeExclude + */ + public static int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final Object object) { + return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null); + } + + /** + *

              + * Uses reflection to build a valid hash code from the fields of {@code object}. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * If the TestTransients parameter is set to true, transient members will be tested, otherwise they + * are ignored, as they are likely derived fields, and not part of the value of the Object. + *

              + * + *

              + * Static fields will not be tested. Superclass fields will be included. + *

              + * + *

              + * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, + * however this is not vital. Prime numbers are preferred, especially for the multiplier. + *

              + * + * @param initialNonZeroOddNumber + * a non-zero, odd number used as the initial value. This will be the returned + * value if no fields are found to include in the hash code + * @param multiplierNonZeroOddNumber + * a non-zero, odd number used as the multiplier + * @param object + * the Object to create a hashCode for + * @param testTransients + * whether to include transient fields + * @return int hash code + * @throws IllegalArgumentException + * if the Object is null + * @throws IllegalArgumentException + * if the number is zero or even + * + * @see HashCodeExclude + */ + public static int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final Object object, + final boolean testTransients) { + return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null); + } + + /** + *

              + * Uses reflection to build a valid hash code from the fields of {@code object}. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * If the TestTransients parameter is set to true, transient members will be tested, otherwise they + * are ignored, as they are likely derived fields, and not part of the value of the Object. + *

              + * + *

              + * Static fields will not be included. Superclass fields will be included up to and including the specified + * superclass. A null superclass is treated as java.lang.Object. + *

              + * + *

              + * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, + * however this is not vital. Prime numbers are preferred, especially for the multiplier. + *

              + * + * @param + * the type of the object involved + * @param initialNonZeroOddNumber + * a non-zero, odd number used as the initial value. This will be the returned + * value if no fields are found to include in the hash code + * @param multiplierNonZeroOddNumber + * a non-zero, odd number used as the multiplier + * @param object + * the Object to create a hashCode for + * @param testTransients + * whether to include transient fields + * @param reflectUpToClass + * the superclass to reflect up to (inclusive), may be null + * @param excludeFields + * array of field names to exclude from use in calculation of hash code + * @return int hash code + * @throws IllegalArgumentException + * if the Object is null + * @throws IllegalArgumentException + * if the number is zero or even + * + * @see HashCodeExclude + * @since 2.0 + */ + public static int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final T object, + final boolean testTransients, final Class reflectUpToClass, final String... excludeFields) { + + if (object == null) { + throw new IllegalArgumentException("The object to build a hash code for must not be null"); + } + final HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber); + Class clazz = object.getClass(); + reflectionAppend(object, clazz, builder, testTransients, excludeFields); + while (clazz.getSuperclass() != null && clazz != reflectUpToClass) { + clazz = clazz.getSuperclass(); + reflectionAppend(object, clazz, builder, testTransients, excludeFields); + } + return builder.toHashCode(); + } + + /** + *

              + * Uses reflection to build a valid hash code from the fields of {@code object}. + *

              + * + *

              + * This constructor uses two hard coded choices for the constants needed to build a hash code. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * If the TestTransients parameter is set to true, transient members will be tested, otherwise they + * are ignored, as they are likely derived fields, and not part of the value of the Object. + *

              + * + *

              + * Static fields will not be tested. Superclass fields will be included. If no fields are found to include + * in the hash code, the result of this method will be constant. + *

              + * + * @param object + * the Object to create a hashCode for + * @param testTransients + * whether to include transient fields + * @return int hash code + * @throws IllegalArgumentException + * if the object is null + * + * @see HashCodeExclude + */ + public static int reflectionHashCode(final Object object, final boolean testTransients) { + return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object, + testTransients, null); + } + + /** + *

              + * Uses reflection to build a valid hash code from the fields of {@code object}. + *

              + * + *

              + * This constructor uses two hard coded choices for the constants needed to build a hash code. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * Transient members will be not be used, as they are likely derived fields, and not part of the value of the + * Object. + *

              + * + *

              + * Static fields will not be tested. Superclass fields will be included. If no fields are found to include + * in the hash code, the result of this method will be constant. + *

              + * + * @param object + * the Object to create a hashCode for + * @param excludeFields + * Collection of String field names to exclude from use in calculation of hash code + * @return int hash code + * @throws IllegalArgumentException + * if the object is null + * + * @see HashCodeExclude + */ + public static int reflectionHashCode(final Object object, final Collection excludeFields) { + return reflectionHashCode(object, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + // ------------------------------------------------------------------------- + + /** + *

              + * Uses reflection to build a valid hash code from the fields of {@code object}. + *

              + * + *

              + * This constructor uses two hard coded choices for the constants needed to build a hash code. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * Transient members will be not be used, as they are likely derived fields, and not part of the value of the + * Object. + *

              + * + *

              + * Static fields will not be tested. Superclass fields will be included. If no fields are found to include + * in the hash code, the result of this method will be constant. + *

              + * + * @param object + * the Object to create a hashCode for + * @param excludeFields + * array of field names to exclude from use in calculation of hash code + * @return int hash code + * @throws IllegalArgumentException + * if the object is null + * + * @see HashCodeExclude + */ + public static int reflectionHashCode(final Object object, final String... excludeFields) { + return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object, false, + null, excludeFields); + } + + /** + *

              + * Registers the given object. Used by the reflection methods to avoid infinite loops. + *

              + * + * @param value + * The object to register. + */ + private static void register(final Object value) { + Set registry = getRegistry(); + if (registry == null) { + registry = new HashSet<>(); + REGISTRY.set(registry); + } + registry.add(new IDKey(value)); + } + + /** + *

              + * Unregisters the given object. + *

              + * + *

              + * Used by the reflection methods to avoid infinite loops. + * + * @param value + * The object to unregister. + * @since 2.3 + */ + private static void unregister(final Object value) { + final Set registry = getRegistry(); + if (registry != null) { + registry.remove(new IDKey(value)); + if (registry.isEmpty()) { + REGISTRY.remove(); + } + } + } + + /** + * Constant to use in building the hashCode. + */ + private final int iConstant; + + /** + * Running total of the hashCode. + */ + private int iTotal = 0; + + /** + *

              + * Uses two hard coded choices for the constants needed to build a hashCode. + *

              + */ + public HashCodeBuilder() { + iConstant = 37; + iTotal = 17; + } + + /** + *

              + * Two randomly chosen, odd numbers must be passed in. Ideally these should be different for each class, + * however this is not vital. + *

              + * + *

              + * Prime numbers are preferred, especially for the multiplier. + *

              + * + * @param initialOddNumber + * an odd number used as the initial value + * @param multiplierOddNumber + * an odd number used as the multiplier + * @throws IllegalArgumentException + * if the number is even + */ + public HashCodeBuilder(final int initialOddNumber, final int multiplierOddNumber) { + Validate.isTrue(initialOddNumber % 2 != 0, "HashCodeBuilder requires an odd initial value"); + Validate.isTrue(multiplierOddNumber % 2 != 0, "HashCodeBuilder requires an odd multiplier"); + iConstant = multiplierOddNumber; + iTotal = initialOddNumber; + } + + /** + *

              + * Append a hashCode for a boolean. + *

              + *

              + * This adds 1 when true, and 0 when false to the hashCode. + *

              + *

              + * This is in contrast to the standard java.lang.Boolean.hashCode handling, which computes + * a hashCode value of 1231 for java.lang.Boolean instances + * that represent true or 1237 for java.lang.Boolean instances + * that represent false. + *

              + *

              + * This is in accordance with the Effective Java design. + *

              + * + * @param value + * the boolean to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final boolean value) { + iTotal = iTotal * iConstant + (value ? 0 : 1); + return this; + } + + /** + *

              + * Append a hashCode for a boolean array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final boolean[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final boolean element : array) { + append(element); + } + } + return this; + } + + // ------------------------------------------------------------------------- + + /** + *

              + * Append a hashCode for a byte. + *

              + * + * @param value + * the byte to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final byte value) { + iTotal = iTotal * iConstant + value; + return this; + } + + // ------------------------------------------------------------------------- + + /** + *

              + * Append a hashCode for a byte array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final byte[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final byte element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Append a hashCode for a char. + *

              + * + * @param value + * the char to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final char value) { + iTotal = iTotal * iConstant + value; + return this; + } + + /** + *

              + * Append a hashCode for a char array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final char[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final char element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Append a hashCode for a double. + *

              + * + * @param value + * the double to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final double value) { + return append(Double.doubleToLongBits(value)); + } + + /** + *

              + * Append a hashCode for a double array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final double[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final double element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Append a hashCode for a float. + *

              + * + * @param value + * the float to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final float value) { + iTotal = iTotal * iConstant + Float.floatToIntBits(value); + return this; + } + + /** + *

              + * Append a hashCode for a float array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final float[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final float element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Append a hashCode for an int. + *

              + * + * @param value + * the int to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final int value) { + iTotal = iTotal * iConstant + value; + return this; + } + + /** + *

              + * Append a hashCode for an int array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final int[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final int element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Append a hashCode for a long. + *

              + * + * @param value + * the long to add to the hashCode + * @return this + */ + // NOTE: This method uses >> and not >>> as Effective Java and + // Long.hashCode do. Ideally we should switch to >>> at + // some stage. There are backwards compat issues, so + // that will have to wait for the time being. cf LANG-342. + public HashCodeBuilder append(final long value) { + iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32))); + return this; + } + + /** + *

              + * Append a hashCode for a long array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final long[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final long element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Append a hashCode for an Object. + *

              + * + * @param object + * the Object to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final Object object) { + if (object == null) { + iTotal = iTotal * iConstant; + + } else { + if (object.getClass().isArray()) { + // factor out array case in order to keep method small enough + // to be inlined + appendArray(object); + } else { + iTotal = iTotal * iConstant + object.hashCode(); + } + } + return this; + } + + /** + *

              + * Append a hashCode for an array. + *

              + * + * @param object + * the array to add to the hashCode + */ + private void appendArray(final Object object) { + // 'Switch' on type of array, to dispatch to the correct handler + // This handles multi dimensional arrays + if (object instanceof long[]) { + append((long[]) object); + } else if (object instanceof int[]) { + append((int[]) object); + } else if (object instanceof short[]) { + append((short[]) object); + } else if (object instanceof char[]) { + append((char[]) object); + } else if (object instanceof byte[]) { + append((byte[]) object); + } else if (object instanceof double[]) { + append((double[]) object); + } else if (object instanceof float[]) { + append((float[]) object); + } else if (object instanceof boolean[]) { + append((boolean[]) object); + } else { + // Not an array of primitives + append((Object[]) object); + } + } + + /** + *

              + * Append a hashCode for an Object array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final Object[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final Object element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Append a hashCode for a short. + *

              + * + * @param value + * the short to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final short value) { + iTotal = iTotal * iConstant + value; + return this; + } + + /** + *

              + * Append a hashCode for a short array. + *

              + * + * @param array + * the array to add to the hashCode + * @return this + */ + public HashCodeBuilder append(final short[] array) { + if (array == null) { + iTotal = iTotal * iConstant; + } else { + for (final short element : array) { + append(element); + } + } + return this; + } + + /** + *

              + * Adds the result of super.hashCode() to this builder. + *

              + * + * @param superHashCode + * the result of calling super.hashCode() + * @return this HashCodeBuilder, used to chain calls. + * @since 2.0 + */ + public HashCodeBuilder appendSuper(final int superHashCode) { + iTotal = iTotal * iConstant + superHashCode; + return this; + } + + /** + *

              + * Return the computed hashCode. + *

              + * + * @return hashCode based on the fields appended + */ + public int toHashCode() { + return iTotal; + } + + /** + * Returns the computed hashCode. + * + * @return hashCode based on the fields appended + * + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toHashCode()); + } + + /** + *

              + * The computed hashCode from toHashCode() is returned due to the likelihood + * of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for + * HashCodeBuilder itself is.

              + * + * @return hashCode based on the fields appended + * @since 2.5 + */ + @Override + public int hashCode() { + return toHashCode(); + } + +} diff --git a/src/org/apache/commons/lang3/builder/HashCodeExclude.java b/src/org/apache/commons/lang3/builder/HashCodeExclude.java new file mode 100644 index 0000000..65d9bef --- /dev/null +++ b/src/org/apache/commons/lang3/builder/HashCodeExclude.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.builder; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Use this annotation to exclude a field from being being used by + * the various reflectionHashcode methods defined on + * {@link HashCodeBuilder}. + * + * @since 3.5 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface HashCodeExclude { + +} diff --git a/src/org/apache/commons/lang3/builder/IDKey.java b/src/org/apache/commons/lang3/builder/IDKey.java new file mode 100644 index 0000000..b66cdb8 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/IDKey.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.builder; + +// adapted from org.apache.axis.utils.IDKey + +/** + * Wrap an identity key (System.identityHashCode()) + * so that an object can only be equal() to itself. + * + * This is necessary to disambiguate the occasional duplicate + * identityHashCodes that can occur. + */ +final class IDKey { + private final Object value; + private final int id; + + /** + * Constructor for IDKey + * @param _value The value + */ + public IDKey(final Object _value) { + // This is the Object hash code + id = System.identityHashCode(_value); + // There have been some cases (LANG-459) that return the + // same identity hash code for different objects. So + // the value is also added to disambiguate these cases. + value = _value; + } + + /** + * returns hash code - i.e. the system identity hashcode. + * @return the hashcode + */ + @Override + public int hashCode() { + return id; + } + + /** + * checks if instances are equal + * @param other The other object to compare to + * @return if the instances are for the same object + */ + @Override + public boolean equals(final Object other) { + if (!(other instanceof IDKey)) { + return false; + } + final IDKey idKey = (IDKey) other; + if (id != idKey.id) { + return false; + } + // Note that identity equals is used. + return value == idKey.value; + } +} diff --git a/src/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java b/src/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java new file mode 100644 index 0000000..df82787 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/MultilineRecursiveToStringStyle.java @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.builder; + +import org.apache.commons.lang3.ClassUtils; + +/** + *

              Works with {@link ToStringBuilder} to create a "deep" toString. + * But instead a single line like the {@link RecursiveToStringStyle} this creates a multiline String + * similar to the {@link ToStringStyle#MULTI_LINE_STYLE}.

              + * + *

              To use this class write code as follows:

              + * + *
              + * public class Job {
              + *   String title;
              + *   ...
              + * }
              + * 
              + * public class Person {
              + *   String name;
              + *   int age;
              + *   boolean smoker;
              + *   Job job;
              + * 
              + *   ...
              + * 
              + *   public String toString() {
              + *     return new ReflectionToStringBuilder(this, new MultilineRecursiveToStringStyle()).toString();
              + *   }
              + * }
              + * 
              + * + *

              + * This will produce a toString of the format:
              + * Person@7f54[
              + *   name=Stephen,
              + *   age=29,
              + *   smoker=false,
              + *   job=Job@43cd2[
              + *     title=Manager
              + *   ]
              + * ] + *
              + *

              + * + * @since 3.4 + */ +public class MultilineRecursiveToStringStyle extends RecursiveToStringStyle { + + /** + * Required for serialization support. + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1L; + + /** Indenting of inner lines. */ + private static final int INDENT = 2; + + /** Current indenting. */ + private int spaces = 2; + + /** + * Constructor. + */ + public MultilineRecursiveToStringStyle() { + super(); + resetIndent(); + } + + /** + * Resets the fields responsible for the line breaks and indenting. + * Must be invoked after changing the {@link #spaces} value. + */ + private void resetIndent() { + setArrayStart("{" + System.lineSeparator() + spacer(spaces)); + setArraySeparator("," + System.lineSeparator() + spacer(spaces)); + setArrayEnd(System.lineSeparator() + spacer(spaces - INDENT) + "}"); + + setContentStart("[" + System.lineSeparator() + spacer(spaces)); + setFieldSeparator("," + System.lineSeparator() + spacer(spaces)); + setContentEnd(System.lineSeparator() + spacer(spaces - INDENT) + "]"); + } + + /** + * Creates a StringBuilder responsible for the indenting. + * + * @param spaces how far to indent + * @return a StringBuilder with {spaces} leading space characters. + */ + private StringBuilder spacer(final int spaces) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < spaces; i++) { + sb.append(" "); + } + return sb; + } + + @Override + public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { + if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && !String.class.equals(value.getClass()) + && accept(value.getClass())) { + spaces += INDENT; + resetIndent(); + buffer.append(ReflectionToStringBuilder.toString(value, this)); + spaces -= INDENT; + resetIndent(); + } else { + super.appendDetail(buffer, fieldName, value); + } + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { + spaces += INDENT; + resetIndent(); + super.appendDetail(buffer, fieldName, array); + spaces -= INDENT; + resetIndent(); + } + +} diff --git a/src/org/apache/commons/lang3/builder/RecursiveToStringStyle.java b/src/org/apache/commons/lang3/builder/RecursiveToStringStyle.java new file mode 100644 index 0000000..b39e9ea --- /dev/null +++ b/src/org/apache/commons/lang3/builder/RecursiveToStringStyle.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import java.util.Collection; + +import org.apache.commons.lang3.ClassUtils; + +/** + *

              Works with {@link ToStringBuilder} to create a "deep" toString.

              + * + *

              To use this class write code as follows:

              + * + *
              + * public class Job {
              + *   String title;
              + *   ...
              + * }
              + * 
              + * public class Person {
              + *   String name;
              + *   int age;
              + *   boolean smoker;
              + *   Job job;
              + *
              + *   ...
              + *
              + *   public String toString() {
              + *     return new ReflectionToStringBuilder(this, new RecursiveToStringStyle()).toString();
              + *   }
              + * }
              + * 
              + * + *

              This will produce a toString of the format: + * Person@7f54[name=Stephen,age=29,smoker=false,job=Job@43cd2[title=Manager]]

              + * + * @since 3.2 + */ +public class RecursiveToStringStyle extends ToStringStyle { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + */ + public RecursiveToStringStyle() { + super(); + } + + @Override + public void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { + if (!ClassUtils.isPrimitiveWrapper(value.getClass()) && + !String.class.equals(value.getClass()) && + accept(value.getClass())) { + buffer.append(ReflectionToStringBuilder.toString(value, this)); + } else { + super.appendDetail(buffer, fieldName, value); + } + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection coll) { + appendClassName(buffer, coll); + appendIdentityHashCode(buffer, coll); + appendDetail(buffer, fieldName, coll.toArray()); + } + + /** + * Returns whether or not to recursively format the given Class. + * By default, this method always returns {@code true}, but may be overwritten by + * sub-classes to filter specific classes. + * + * @param clazz + * The class to test. + * @return Whether or not to recursively format the given Class. + */ + protected boolean accept(final Class clazz) { + return true; + } +} diff --git a/src/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java b/src/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java new file mode 100644 index 0000000..b1952dd --- /dev/null +++ b/src/org/apache/commons/lang3/builder/ReflectionDiffBuilder.java @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import static org.apache.commons.lang3.reflect.FieldUtils.readField; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.reflect.FieldUtils; + +/** + *

              + * Assists in implementing {@link Diffable#diff(Object)} methods. + *

              + *

              + * All non-static, non-transient fields (including inherited fields) + * of the objects to diff are discovered using reflection and compared + * for differences. + *

              + * + *

              + * To use this class, write code as follows: + *

              + * + *
              + * public class Person implements Diffable<Person> {
              + *   String name;
              + *   int age;
              + *   boolean smoker;
              + *   ...
              + *   
              + *   public DiffResult diff(Person obj) {
              + *     // No need for null check, as NullPointerException correct if obj is null
              + *     return new ReflectionDiffBuilder(this, obj, ToStringStyle.SHORT_PREFIX_STYLE)
              + *       .build();
              + *   }
              + * }
              + * 
              + * + *

              + * The {@code ToStringStyle} passed to the constructor is embedded in the + * returned {@code DiffResult} and influences the style of the + * {@code DiffResult.toString()} method. This style choice can be overridden by + * calling {@link DiffResult#toString(ToStringStyle)}. + *

              + * @see Diffable + * @see Diff + * @see DiffResult + * @see ToStringStyle + * @since 3.6 + */ +public class ReflectionDiffBuilder implements Builder { + + private final Object left; + private final Object right; + private final DiffBuilder diffBuilder; + + /** + *

              + * Constructs a builder for the specified objects with the specified style. + *

              + * + *

              + * If {@code lhs == rhs} or {@code lhs.equals(rhs)} then the builder will + * not evaluate any calls to {@code append(...)} and will return an empty + * {@link DiffResult} when {@link #build()} is executed. + *

              + * @param + * type of the objects to diff + * @param lhs + * {@code this} object + * @param rhs + * the object to diff against + * @param style + * the style will use when outputting the objects, {@code null} + * uses the default + * @throws IllegalArgumentException + * if {@code lhs} or {@code rhs} is {@code null} + */ + public ReflectionDiffBuilder(final T lhs, final T rhs, final ToStringStyle style) { + this.left = lhs; + this.right = rhs; + diffBuilder = new DiffBuilder(lhs, rhs, style); + } + + @Override + public DiffResult build() { + if (left.equals(right)) { + return diffBuilder.build(); + } + + appendFields(left.getClass()); + return diffBuilder.build(); + } + + private void appendFields(final Class clazz) { + for (final Field field : FieldUtils.getAllFields(clazz)) { + if (accept(field)) { + try { + diffBuilder.append(field.getName(), readField(field, left, true), + readField(field, right, true)); + } catch (final IllegalAccessException ex) { + //this can't happen. Would get a Security exception instead + //throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage()); + } + } + } + } + + private boolean accept(final Field field) { + if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) { + return false; + } + if (Modifier.isTransient(field.getModifiers())) { + return false; + } + if (Modifier.isStatic(field.getModifiers())) { + return false; + } + return true; + } + +} diff --git a/src/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java b/src/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java new file mode 100644 index 0000000..d40a838 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java @@ -0,0 +1,719 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; + +/** + *

              + * Assists in implementing {@link Object#toString()} methods using reflection. + *

              + *

              + * This class uses reflection to determine the fields to append. Because these fields are usually private, the class + * uses {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)} to + * change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are + * set up correctly. + *

              + *

              + * Using reflection to access (private) fields circumvents any synchronization protection guarding access to these + * fields. If a toString method cannot safely read a field, you should exclude it from the toString method, or use + * synchronization consistent with the class' lock management around the invocation of the method. Take special care to + * exclude non-thread-safe collection classes, because these classes may throw ConcurrentModificationException if + * modified while the toString method is executing. + *

              + *

              + * A typical invocation for this method would look like: + *

              + *
              + * public String toString() {
              + *     return ReflectionToStringBuilder.toString(this);
              + * }
              + * 
              + *

              + * You can also use the builder to debug 3rd party objects: + *

              + *
              + * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));
              + * 
              + *

              + * A subclass can control field output by overriding the methods: + *

              + *
                + *
              • {@link #accept(java.lang.reflect.Field)}
              • + *
              • {@link #getValue(java.lang.reflect.Field)}
              • + *
              + *

              + * For example, this method does not include the password field in the returned String: + *

              + *
              + * public String toString() {
              + *     return (new ReflectionToStringBuilder(this) {
              + *         protected boolean accept(Field f) {
              + *             return super.accept(f) && !f.getName().equals("password");
              + *         }
              + *     }).toString();
              + * }
              + * 
              + *

              + * Alternatively the {@link ToStringExclude} annotation can be used to exclude fields from being incorporated in the + * result. + *

              + *

              + * The exact format of the toString is determined by the {@link ToStringStyle} passed into the constructor. + *

              + * + *

              + * Note: the default {@link ToStringStyle} will only do a "shallow" formatting, i.e. composed objects are not + * further traversed. To get "deep" formatting, use an instance of {@link RecursiveToStringStyle}. + *

              + * + * @since 2.0 + */ +public class ReflectionToStringBuilder extends ToStringBuilder { + + /** + *

              + * Builds a toString value using the default ToStringStyle through reflection. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * Transient members will be not be included, as they are likely derived. Static fields will not be included. + * Superclass fields will be appended. + *

              + * + * @param object + * the Object to be output + * @return the String result + * @throws IllegalArgumentException + * if the Object is null + * + * @see ToStringExclude + */ + public static String toString(final Object object) { + return toString(object, null, false, false, null); + } + + /** + *

              + * Builds a toString value through reflection. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * Transient members will be not be included, as they are likely derived. Static fields will not be included. + * Superclass fields will be appended. + *

              + * + *

              + * If the style is null, the default ToStringStyle is used. + *

              + * + * @param object + * the Object to be output + * @param style + * the style of the toString to create, may be null + * @return the String result + * @throws IllegalArgumentException + * if the Object or ToStringStyle is null + * + * @see ToStringExclude + */ + public static String toString(final Object object, final ToStringStyle style) { + return toString(object, style, false, false, null); + } + + /** + *

              + * Builds a toString value through reflection. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * If the outputTransients is true, transient members will be output, otherwise they + * are ignored, as they are likely derived fields, and not part of the value of the Object. + *

              + * + *

              + * Static fields will not be included. Superclass fields will be appended. + *

              + * + *

              + * If the style is null, the default ToStringStyle is used. + *

              + * + * @param object + * the Object to be output + * @param style + * the style of the toString to create, may be null + * @param outputTransients + * whether to include transient fields + * @return the String result + * @throws IllegalArgumentException + * if the Object is null + * + * @see ToStringExclude + */ + public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients) { + return toString(object, style, outputTransients, false, null); + } + + /** + *

              + * Builds a toString value through reflection. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * If the outputTransients is true, transient fields will be output, otherwise they + * are ignored, as they are likely derived fields, and not part of the value of the Object. + *

              + * + *

              + * If the outputStatics is true, static fields will be output, otherwise they are + * ignored. + *

              + * + *

              + * Static fields will not be included. Superclass fields will be appended. + *

              + * + *

              + * If the style is null, the default ToStringStyle is used. + *

              + * + * @param object + * the Object to be output + * @param style + * the style of the toString to create, may be null + * @param outputTransients + * whether to include transient fields + * @param outputStatics + * whether to include static fields + * @return the String result + * @throws IllegalArgumentException + * if the Object is null + * + * @see ToStringExclude + * @since 2.1 + */ + public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients, final boolean outputStatics) { + return toString(object, style, outputTransients, outputStatics, null); + } + + /** + *

              + * Builds a toString value through reflection. + *

              + * + *

              + * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will + * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is + * also not as efficient as testing explicitly. + *

              + * + *

              + * If the outputTransients is true, transient fields will be output, otherwise they + * are ignored, as they are likely derived fields, and not part of the value of the Object. + *

              + * + *

              + * If the outputStatics is true, static fields will be output, otherwise they are + * ignored. + *

              + * + *

              + * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as + * java.lang.Object. + *

              + * + *

              + * If the style is null, the default ToStringStyle is used. + *

              + * + * @param + * the type of the object + * @param object + * the Object to be output + * @param style + * the style of the toString to create, may be null + * @param outputTransients + * whether to include transient fields + * @param outputStatics + * whether to include static fields + * @param reflectUpToClass + * the superclass to reflect up to (inclusive), may be null + * @return the String result + * @throws IllegalArgumentException + * if the Object is null + * + * @see ToStringExclude + * @since 2.1 + */ + public static String toString( + final T object, final ToStringStyle style, final boolean outputTransients, + final boolean outputStatics, final Class reflectUpToClass) { + return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics) + .toString(); + } + + /** + * Builds a String for a toString method excluding the given field names. + * + * @param object + * The object to "toString". + * @param excludeFieldNames + * The field names to exclude. Null excludes nothing. + * @return The toString value. + */ + public static String toStringExclude(final Object object, final Collection excludeFieldNames) { + return toStringExclude(object, toNoNullStringArray(excludeFieldNames)); + } + + /** + * Converts the given Collection into an array of Strings. The returned array does not contain null + * entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element + * is null. + * + * @param collection + * The collection to convert + * @return A new array of Strings. + */ + static String[] toNoNullStringArray(final Collection collection) { + if (collection == null) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + return toNoNullStringArray(collection.toArray()); + } + + /** + * Returns a new array of Strings without null elements. Internal method used to normalize exclude lists + * (arrays and collections). Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} + * if an array element is null. + * + * @param array + * The array to check + * @return The given array or a new array without null. + */ + static String[] toNoNullStringArray(final Object[] array) { + final List list = new ArrayList<>(array.length); + for (final Object e : array) { + if (e != null) { + list.add(e.toString()); + } + } + return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); + } + + + /** + * Builds a String for a toString method excluding the given field names. + * + * @param object + * The object to "toString". + * @param excludeFieldNames + * The field names to exclude + * @return The toString value. + */ + public static String toStringExclude(final Object object, final String... excludeFieldNames) { + return new ReflectionToStringBuilder(object).setExcludeFieldNames(excludeFieldNames).toString(); + } + + private static Object checkNotNull(final Object obj) { + if (obj == null) { + throw new IllegalArgumentException("The Object passed in should not be null."); + } + return obj; + } + + /** + * Whether or not to append static fields. + */ + private boolean appendStatics = false; + + /** + * Whether or not to append transient fields. + */ + private boolean appendTransients = false; + + /** + * Which field names to exclude from output. Intended for fields like "password". + * + * @since 3.0 this is protected instead of private + */ + protected String[] excludeFieldNames; + + /** + * The last super class to stop appending fields for. + */ + private Class upToClass = null; + + /** + *

              + * Constructor. + *

              + * + *

              + * This constructor outputs using the default style set with setDefaultStyle. + *

              + * + * @param object + * the Object to build a toString for, must not be null + * @throws IllegalArgumentException + * if the Object passed in is null + */ + public ReflectionToStringBuilder(final Object object) { + super(checkNotNull(object)); + } + + /** + *

              + * Constructor. + *

              + * + *

              + * If the style is null, the default style is used. + *

              + * + * @param object + * the Object to build a toString for, must not be null + * @param style + * the style of the toString to create, may be null + * @throws IllegalArgumentException + * if the Object passed in is null + */ + public ReflectionToStringBuilder(final Object object, final ToStringStyle style) { + super(checkNotNull(object), style); + } + + /** + *

              + * Constructor. + *

              + * + *

              + * If the style is null, the default style is used. + *

              + * + *

              + * If the buffer is null, a new one is created. + *

              + * + * @param object + * the Object to build a toString for + * @param style + * the style of the toString to create, may be null + * @param buffer + * the StringBuffer to populate, may be null + * @throws IllegalArgumentException + * if the Object passed in is null + */ + public ReflectionToStringBuilder(final Object object, final ToStringStyle style, final StringBuffer buffer) { + super(checkNotNull(object), style, buffer); + } + + /** + * Constructor. + * + * @param + * the type of the object + * @param object + * the Object to build a toString for + * @param style + * the style of the toString to create, may be null + * @param buffer + * the StringBuffer to populate, may be null + * @param reflectUpToClass + * the superclass to reflect up to (inclusive), may be null + * @param outputTransients + * whether to include transient fields + * @param outputStatics + * whether to include static fields + * @since 2.1 + */ + public ReflectionToStringBuilder( + final T object, final ToStringStyle style, final StringBuffer buffer, + final Class reflectUpToClass, final boolean outputTransients, final boolean outputStatics) { + super(checkNotNull(object), style, buffer); + this.setUpToClass(reflectUpToClass); + this.setAppendTransients(outputTransients); + this.setAppendStatics(outputStatics); + } + + /** + * Returns whether or not to append the given Field. + *
                + *
              • Transient fields are appended only if {@link #isAppendTransients()} returns true. + *
              • Static fields are appended only if {@link #isAppendStatics()} returns true. + *
              • Inner class fields are not appended.
              • + *
              + * + * @param field + * The Field to test. + * @return Whether or not to append the given Field. + */ + protected boolean accept(final Field field) { + if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) { + // Reject field from inner class. + return false; + } + if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) { + // Reject transient fields. + return false; + } + if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) { + // Reject static fields. + return false; + } + if (this.excludeFieldNames != null + && Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) { + // Reject fields from the getExcludeFieldNames list. + return false; + } + if(field.isAnnotationPresent(ToStringExclude.class)) { + return false; + } + return true; + } + + /** + *

              + * Appends the fields and values defined by the given object of the given Class. + *

              + * + *

              + * If a cycle is detected as an object is "toString()'ed", such an object is rendered as if + * Object.toString() had been called and not implemented by the object. + *

              + * + * @param clazz + * The class of object parameter + */ + protected void appendFieldsIn(final Class clazz) { + if (clazz.isArray()) { + this.reflectionAppendArray(this.getObject()); + return; + } + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (final Field field : fields) { + final String fieldName = field.getName(); + if (this.accept(field)) { + try { + // Warning: Field.get(Object) creates wrappers objects + // for primitive types. + final Object fieldValue = this.getValue(field); + this.append(fieldName, fieldValue); + } catch (final IllegalAccessException ex) { + //this can't happen. Would get a Security exception + // instead + //throw a runtime exception in case the impossible + // happens. + throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage()); + } + } + } + } + + /** + * @return Returns the excludeFieldNames. + */ + public String[] getExcludeFieldNames() { + return this.excludeFieldNames.clone(); + } + + /** + *

              + * Gets the last super class to stop appending fields for. + *

              + * + * @return The last super class to stop appending fields for. + */ + public Class getUpToClass() { + return this.upToClass; + } + + /** + *

              + * Calls java.lang.reflect.Field.get(Object). + *

              + * + * @param field + * The Field to query. + * @return The Object from the given Field. + * + * @throws IllegalArgumentException + * see {@link java.lang.reflect.Field#get(Object)} + * @throws IllegalAccessException + * see {@link java.lang.reflect.Field#get(Object)} + * + * @see java.lang.reflect.Field#get(Object) + */ + protected Object getValue(final Field field) throws IllegalArgumentException, IllegalAccessException { + return field.get(this.getObject()); + } + + /** + *

              + * Gets whether or not to append static fields. + *

              + * + * @return Whether or not to append static fields. + * @since 2.1 + */ + public boolean isAppendStatics() { + return this.appendStatics; + } + + /** + *

              + * Gets whether or not to append transient fields. + *

              + * + * @return Whether or not to append transient fields. + */ + public boolean isAppendTransients() { + return this.appendTransients; + } + + /** + *

              + * Append to the toString an Object array. + *

              + * + * @param array + * the array to add to the toString + * @return this + */ + public ReflectionToStringBuilder reflectionAppendArray(final Object array) { + this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array); + return this; + } + + /** + *

              + * Sets whether or not to append static fields. + *

              + * + * @param appendStatics + * Whether or not to append static fields. + * @since 2.1 + */ + public void setAppendStatics(final boolean appendStatics) { + this.appendStatics = appendStatics; + } + + /** + *

              + * Sets whether or not to append transient fields. + *

              + * + * @param appendTransients + * Whether or not to append transient fields. + */ + public void setAppendTransients(final boolean appendTransients) { + this.appendTransients = appendTransients; + } + + /** + * Sets the field names to exclude. + * + * @param excludeFieldNamesParam + * The excludeFieldNames to excluding from toString or null. + * @return this + */ + public ReflectionToStringBuilder setExcludeFieldNames(final String... excludeFieldNamesParam) { + if (excludeFieldNamesParam == null) { + this.excludeFieldNames = null; + } else { + //clone and remove nulls + this.excludeFieldNames = toNoNullStringArray(excludeFieldNamesParam); + Arrays.sort(this.excludeFieldNames); + } + return this; + } + + /** + *

              + * Sets the last super class to stop appending fields for. + *

              + * + * @param clazz + * The last super class to stop appending fields for. + */ + public void setUpToClass(final Class clazz) { + if (clazz != null) { + final Object object = getObject(); + if (object != null && clazz.isInstance(object) == false) { + throw new IllegalArgumentException("Specified class is not a superclass of the object"); + } + } + this.upToClass = clazz; + } + + /** + *

              + * Gets the String built by this builder. + *

              + * + * @return the built string + */ + @Override + public String toString() { + if (this.getObject() == null) { + return this.getStyle().getNullText(); + } + Class clazz = this.getObject().getClass(); + this.appendFieldsIn(clazz); + while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) { + clazz = clazz.getSuperclass(); + this.appendFieldsIn(clazz); + } + return super.toString(); + } + +} diff --git a/src/org/apache/commons/lang3/builder/StandardToStringStyle.java b/src/org/apache/commons/lang3/builder/StandardToStringStyle.java new file mode 100644 index 0000000..b9ba30c --- /dev/null +++ b/src/org/apache/commons/lang3/builder/StandardToStringStyle.java @@ -0,0 +1,559 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +/** + *

              Works with {@link ToStringBuilder} to create a toString.

              + * + *

              This class is intended to be used as a singleton. + * There is no need to instantiate a new style each time. + * Simply instantiate the class once, customize the values as required, and + * store the result in a public static final variable for the rest of the + * program to access.

              + * + * @since 1.0 + */ +public class StandardToStringStyle extends ToStringStyle { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + */ + public StandardToStringStyle() { + super(); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use the class name.

              + * + * @return the current useClassName flag + */ + @Override + public boolean isUseClassName() { // NOPMD as this is implementing the abstract class + return super.isUseClassName(); + } + + /** + *

              Sets whether to use the class name.

              + * + * @param useClassName the new useClassName flag + */ + @Override + public void setUseClassName(final boolean useClassName) { // NOPMD as this is implementing the abstract class + super.setUseClassName(useClassName); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to output short or long class names.

              + * + * @return the current useShortClassName flag + * @since 2.0 + */ + @Override + public boolean isUseShortClassName() { // NOPMD as this is implementing the abstract class + return super.isUseShortClassName(); + } + + /** + *

              Sets whether to output short or long class names.

              + * + * @param useShortClassName the new useShortClassName flag + * @since 2.0 + */ + @Override + public void setUseShortClassName(final boolean useShortClassName) { // NOPMD as this is implementing the abstract class + super.setUseShortClassName(useShortClassName); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use the identity hash code.

              + * @return the current useIdentityHashCode flag + */ + @Override + public boolean isUseIdentityHashCode() { // NOPMD as this is implementing the abstract class + return super.isUseIdentityHashCode(); + } + + /** + *

              Sets whether to use the identity hash code.

              + * + * @param useIdentityHashCode the new useIdentityHashCode flag + */ + @Override + public void setUseIdentityHashCode(final boolean useIdentityHashCode) { // NOPMD as this is implementing the abstract class + super.setUseIdentityHashCode(useIdentityHashCode); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use the field names passed in.

              + * + * @return the current useFieldNames flag + */ + @Override + public boolean isUseFieldNames() { // NOPMD as this is implementing the abstract class + return super.isUseFieldNames(); + } + + /** + *

              Sets whether to use the field names passed in.

              + * + * @param useFieldNames the new useFieldNames flag + */ + @Override + public void setUseFieldNames(final boolean useFieldNames) { // NOPMD as this is implementing the abstract class + super.setUseFieldNames(useFieldNames); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use full detail when the caller doesn't + * specify.

              + * + * @return the current defaultFullDetail flag + */ + @Override + public boolean isDefaultFullDetail() { // NOPMD as this is implementing the abstract class + return super.isDefaultFullDetail(); + } + + /** + *

              Sets whether to use full detail when the caller doesn't + * specify.

              + * + * @param defaultFullDetail the new defaultFullDetail flag + */ + @Override + public void setDefaultFullDetail(final boolean defaultFullDetail) { // NOPMD as this is implementing the abstract class + super.setDefaultFullDetail(defaultFullDetail); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to output array content detail.

              + * + * @return the current array content detail setting + */ + @Override + public boolean isArrayContentDetail() { // NOPMD as this is implementing the abstract class + return super.isArrayContentDetail(); + } + + /** + *

              Sets whether to output array content detail.

              + * + * @param arrayContentDetail the new arrayContentDetail flag + */ + @Override + public void setArrayContentDetail(final boolean arrayContentDetail) { // NOPMD as this is implementing the abstract class + super.setArrayContentDetail(arrayContentDetail); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the array start text.

              + * + * @return the current array start text + */ + @Override + public String getArrayStart() { // NOPMD as this is implementing the abstract class + return super.getArrayStart(); + } + + /** + *

              Sets the array start text.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param arrayStart the new array start text + */ + @Override + public void setArrayStart(final String arrayStart) { // NOPMD as this is implementing the abstract class + super.setArrayStart(arrayStart); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the array end text.

              + * + * @return the current array end text + */ + @Override + public String getArrayEnd() { // NOPMD as this is implementing the abstract class + return super.getArrayEnd(); + } + + /** + *

              Sets the array end text.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param arrayEnd the new array end text + */ + @Override + public void setArrayEnd(final String arrayEnd) { // NOPMD as this is implementing the abstract class + super.setArrayEnd(arrayEnd); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the array separator text.

              + * + * @return the current array separator text + */ + @Override + public String getArraySeparator() { // NOPMD as this is implementing the abstract class + return super.getArraySeparator(); + } + + /** + *

              Sets the array separator text.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param arraySeparator the new array separator text + */ + @Override + public void setArraySeparator(final String arraySeparator) { // NOPMD as this is implementing the abstract class + super.setArraySeparator(arraySeparator); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the content start text.

              + * + * @return the current content start text + */ + @Override + public String getContentStart() { // NOPMD as this is implementing the abstract class + return super.getContentStart(); + } + + /** + *

              Sets the content start text.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param contentStart the new content start text + */ + @Override + public void setContentStart(final String contentStart) { // NOPMD as this is implementing the abstract class + super.setContentStart(contentStart); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the content end text.

              + * + * @return the current content end text + */ + @Override + public String getContentEnd() { // NOPMD as this is implementing the abstract class + return super.getContentEnd(); + } + + /** + *

              Sets the content end text.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param contentEnd the new content end text + */ + @Override + public void setContentEnd(final String contentEnd) { // NOPMD as this is implementing the abstract class + super.setContentEnd(contentEnd); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the field name value separator text.

              + * + * @return the current field name value separator text + */ + @Override + public String getFieldNameValueSeparator() { // NOPMD as this is implementing the abstract class + return super.getFieldNameValueSeparator(); + } + + /** + *

              Sets the field name value separator text.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param fieldNameValueSeparator the new field name value separator text + */ + @Override + public void setFieldNameValueSeparator(final String fieldNameValueSeparator) { // NOPMD as this is implementing the abstract class + super.setFieldNameValueSeparator(fieldNameValueSeparator); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the field separator text.

              + * + * @return the current field separator text + */ + @Override + public String getFieldSeparator() { // NOPMD as this is implementing the abstract class + return super.getFieldSeparator(); + } + + /** + *

              Sets the field separator text.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param fieldSeparator the new field separator text + */ + @Override + public void setFieldSeparator(final String fieldSeparator) { // NOPMD as this is implementing the abstract class + super.setFieldSeparator(fieldSeparator); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether the field separator should be added at the start + * of each buffer.

              + * + * @return the fieldSeparatorAtStart flag + * @since 2.0 + */ + @Override + public boolean isFieldSeparatorAtStart() { // NOPMD as this is implementing the abstract class + return super.isFieldSeparatorAtStart(); + } + + /** + *

              Sets whether the field separator should be added at the start + * of each buffer.

              + * + * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag + * @since 2.0 + */ + @Override + public void setFieldSeparatorAtStart(final boolean fieldSeparatorAtStart) { // NOPMD as this is implementing the abstract class + super.setFieldSeparatorAtStart(fieldSeparatorAtStart); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether the field separator should be added at the end + * of each buffer.

              + * + * @return fieldSeparatorAtEnd flag + * @since 2.0 + */ + @Override + public boolean isFieldSeparatorAtEnd() { // NOPMD as this is implementing the abstract class + return super.isFieldSeparatorAtEnd(); + } + + /** + *

              Sets whether the field separator should be added at the end + * of each buffer.

              + * + * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag + * @since 2.0 + */ + @Override + public void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) { // NOPMD as this is implementing the abstract class + super.setFieldSeparatorAtEnd(fieldSeparatorAtEnd); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the text to output when null found.

              + * + * @return the current text to output when null found + */ + @Override + public String getNullText() { // NOPMD as this is implementing the abstract class + return super.getNullText(); + } + + /** + *

              Sets the text to output when null found.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param nullText the new text to output when null found + */ + @Override + public void setNullText(final String nullText) { // NOPMD as this is implementing the abstract class + super.setNullText(nullText); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the text to output when a Collection, + * Map or Array size is output.

              + * + *

              This is output before the size value.

              + * + * @return the current start of size text + */ + @Override + public String getSizeStartText() { // NOPMD as this is implementing the abstract class + return super.getSizeStartText(); + } + + /** + *

              Sets the start text to output when a Collection, + * Map or Array size is output.

              + * + *

              This is output before the size value.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param sizeStartText the new start of size text + */ + @Override + public void setSizeStartText(final String sizeStartText) { // NOPMD as this is implementing the abstract class + super.setSizeStartText(sizeStartText); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the end text to output when a Collection, + * Map or Array size is output.

              + * + *

              This is output after the size value.

              + * + * @return the current end of size text + */ + @Override + public String getSizeEndText() { // NOPMD as this is implementing the abstract class + return super.getSizeEndText(); + } + + /** + *

              Sets the end text to output when a Collection, + * Map or Array size is output.

              + * + *

              This is output after the size value.

              + * + *

              null is accepted, but will be converted + * to an empty String.

              + * + * @param sizeEndText the new end of size text + */ + @Override + public void setSizeEndText(final String sizeEndText) { // NOPMD as this is implementing the abstract class + super.setSizeEndText(sizeEndText); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the start text to output when an Object is + * output in summary mode.

              + * + *

              This is output before the size value.

              + * + * @return the current start of summary text + */ + @Override + public String getSummaryObjectStartText() { // NOPMD as this is implementing the abstract class + return super.getSummaryObjectStartText(); + } + + /** + *

              Sets the start text to output when an Object is + * output in summary mode.

              + * + *

              This is output before the size value.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param summaryObjectStartText the new start of summary text + */ + @Override + public void setSummaryObjectStartText(final String summaryObjectStartText) { // NOPMD as this is implementing the abstract class + super.setSummaryObjectStartText(summaryObjectStartText); + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the end text to output when an Object is + * output in summary mode.

              + * + *

              This is output after the size value.

              + * + * @return the current end of summary text + */ + @Override + public String getSummaryObjectEndText() { // NOPMD as this is implementing the abstract class + return super.getSummaryObjectEndText(); + } + + /** + *

              Sets the end text to output when an Object is + * output in summary mode.

              + * + *

              This is output after the size value.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param summaryObjectEndText the new end of summary text + */ + @Override + public void setSummaryObjectEndText(final String summaryObjectEndText) { // NOPMD as this is implementing the abstract class + super.setSummaryObjectEndText(summaryObjectEndText); + } + + //--------------------------------------------------------------------- + +} diff --git a/src/org/apache/commons/lang3/builder/ToStringBuilder.java b/src/org/apache/commons/lang3/builder/ToStringBuilder.java new file mode 100644 index 0000000..4363751 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/ToStringBuilder.java @@ -0,0 +1,1079 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import org.apache.commons.lang3.ObjectUtils; + +/** + *

              Assists in implementing {@link Object#toString()} methods.

              + * + *

              This class enables a good and consistent toString() to be built for any + * class or object. This class aims to simplify the process by:

              + *
                + *
              • allowing field names
              • + *
              • handling all types consistently
              • + *
              • handling nulls consistently
              • + *
              • outputting arrays and multi-dimensional arrays
              • + *
              • enabling the detail level to be controlled for Objects and Collections
              • + *
              • handling class hierarchies
              • + *
              + * + *

              To use this class write code as follows:

              + * + *
              + * public class Person {
              + *   String name;
              + *   int age;
              + *   boolean smoker;
              + *
              + *   ...
              + *
              + *   public String toString() {
              + *     return new ToStringBuilder(this).
              + *       append("name", name).
              + *       append("age", age).
              + *       append("smoker", smoker).
              + *       toString();
              + *   }
              + * }
              + * 
              + * + *

              This will produce a toString of the format: + * Person@7f54[name=Stephen,age=29,smoker=false]

              + * + *

              To add the superclass toString, use {@link #appendSuper}. + * To append the toString from an object that is delegated + * to (or any other object), use {@link #appendToString}.

              + * + *

              Alternatively, there is a method that uses reflection to determine + * the fields to test. Because these fields are usually private, the method, + * reflectionToString, uses AccessibleObject.setAccessible to + * change the visibility of the fields. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than testing explicitly.

              + * + *

              A typical invocation for this method would look like:

              + * + *
              + * public String toString() {
              + *   return ToStringBuilder.reflectionToString(this);
              + * }
              + * 
              + * + *

              You can also use the builder to debug 3rd party objects:

              + * + *
              + * System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));
              + * 
              + * + *

              The exact format of the toString is determined by + * the {@link ToStringStyle} passed into the constructor.

              + * + * @since 1.0 + */ +public class ToStringBuilder implements Builder { + + /** + * The default style of output to use, not null. + */ + private static volatile ToStringStyle defaultStyle = ToStringStyle.DEFAULT_STYLE; + + //---------------------------------------------------------------------------- + + /** + *

              Gets the default ToStringStyle to use.

              + * + *

              This method gets a singleton default value, typically for the whole JVM. + * Changing this default should generally only be done during application startup. + * It is recommended to pass a ToStringStyle to the constructor instead + * of using this global default.

              + * + *

              This method can be used from multiple threads. + * Internally, a volatile variable is used to provide the guarantee + * that the latest value set using {@link #setDefaultStyle} is the value returned. + * It is strongly recommended that the default style is only changed during application startup.

              + * + *

              One reason for changing the default could be to have a verbose style during + * development and a compact style in production.

              + * + * @return the default ToStringStyle, never null + */ + public static ToStringStyle getDefaultStyle() { + return defaultStyle; + } + + /** + *

              Sets the default ToStringStyle to use.

              + * + *

              This method sets a singleton default value, typically for the whole JVM. + * Changing this default should generally only be done during application startup. + * It is recommended to pass a ToStringStyle to the constructor instead + * of changing this global default.

              + * + *

              This method is not intended for use from multiple threads. + * Internally, a volatile variable is used to provide the guarantee + * that the latest value set is the value returned from {@link #getDefaultStyle}.

              + * + * @param style the default ToStringStyle + * @throws IllegalArgumentException if the style is null + */ + public static void setDefaultStyle(final ToStringStyle style) { + if (style == null) { + throw new IllegalArgumentException("The style must not be null"); + } + defaultStyle = style; + } + + //---------------------------------------------------------------------------- + /** + *

              Uses ReflectionToStringBuilder to generate a + * toString for the specified object.

              + * + * @param object the Object to be output + * @return the String result + * @see ReflectionToStringBuilder#toString(Object) + */ + public static String reflectionToString(final Object object) { + return ReflectionToStringBuilder.toString(object); + } + + /** + *

              Uses ReflectionToStringBuilder to generate a + * toString for the specified object.

              + * + * @param object the Object to be output + * @param style the style of the toString to create, may be null + * @return the String result + * @see ReflectionToStringBuilder#toString(Object,ToStringStyle) + */ + public static String reflectionToString(final Object object, final ToStringStyle style) { + return ReflectionToStringBuilder.toString(object, style); + } + + /** + *

              Uses ReflectionToStringBuilder to generate a + * toString for the specified object.

              + * + * @param object the Object to be output + * @param style the style of the toString to create, may be null + * @param outputTransients whether to include transient fields + * @return the String result + * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean) + */ + public static String reflectionToString(final Object object, final ToStringStyle style, final boolean outputTransients) { + return ReflectionToStringBuilder.toString(object, style, outputTransients, false, null); + } + + /** + *

              Uses ReflectionToStringBuilder to generate a + * toString for the specified object.

              + * + * @param the type of the object + * @param object the Object to be output + * @param style the style of the toString to create, may be null + * @param outputTransients whether to include transient fields + * @param reflectUpToClass the superclass to reflect up to (inclusive), may be null + * @return the String result + * @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean,boolean,Class) + * @since 2.0 + */ + public static String reflectionToString( + final T object, + final ToStringStyle style, + final boolean outputTransients, + final Class reflectUpToClass) { + return ReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass); + } + + //---------------------------------------------------------------------------- + + /** + * Current toString buffer, not null. + */ + private final StringBuffer buffer; + /** + * The object being output, may be null. + */ + private final Object object; + /** + * The style of output to use, not null. + */ + private final ToStringStyle style; + + /** + *

              Constructs a builder for the specified object using the default output style.

              + * + *

              This default style is obtained from {@link #getDefaultStyle()}.

              + * + * @param object the Object to build a toString for, not recommended to be null + */ + public ToStringBuilder(final Object object) { + this(object, null, null); + } + + /** + *

              Constructs a builder for the specified object using the a defined output style.

              + * + *

              If the style is null, the default style is used.

              + * + * @param object the Object to build a toString for, not recommended to be null + * @param style the style of the toString to create, null uses the default style + */ + public ToStringBuilder(final Object object, final ToStringStyle style) { + this(object, style, null); + } + + /** + *

              Constructs a builder for the specified object.

              + * + *

              If the style is null, the default style is used.

              + * + *

              If the buffer is null, a new one is created.

              + * + * @param object the Object to build a toString for, not recommended to be null + * @param style the style of the toString to create, null uses the default style + * @param buffer the StringBuffer to populate, may be null + */ + public ToStringBuilder(final Object object, ToStringStyle style, StringBuffer buffer) { + if (style == null) { + style = getDefaultStyle(); + } + if (buffer == null) { + buffer = new StringBuffer(512); + } + this.buffer = buffer; + this.style = style; + this.object = object; + + style.appendStart(buffer, object); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a boolean + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final boolean value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a boolean + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final boolean[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a byte + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final byte value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a byte + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final byte[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a char + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final char value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a char + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final char[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a double + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final double value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a double + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final double[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a float + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final float value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a float + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final float[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString an int + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final int value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString an int + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final int[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a long + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final long value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a long + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final long[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString an Object + * value.

              + * + * @param obj the value to add to the toString + * @return this + */ + public ToStringBuilder append(final Object obj) { + style.append(buffer, null, obj, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString an Object + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final Object[] array) { + style.append(buffer, null, array, null); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a short + * value.

              + * + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final short value) { + style.append(buffer, null, value); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a short + * array.

              + * + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final short[] array) { + style.append(buffer, null, array, null); + return this; + } + + /** + *

              Append to the toString a boolean + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final boolean value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString a boolean + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the hashCode + * @return this + */ + public ToStringBuilder append(final String fieldName, final boolean[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString a boolean + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final boolean[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString an byte + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final byte value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString a byte array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final byte[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString a byte + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array. + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final byte[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString a char + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final char value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString a char + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final char[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString a char + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final char[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString a double + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final double value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString a double + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final double[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString a double + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final double[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString an float + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final float value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString a float + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final float[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString a float + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final float[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString an int + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final int value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString an int + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final int[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString an int + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final int[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString a long + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final long value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString a long + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final long[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString a long + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final long[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString an Object + * value.

              + * + * @param fieldName the field name + * @param obj the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final Object obj) { + style.append(buffer, fieldName, obj, null); + return this; + } + + /** + *

              Append to the toString an Object + * value.

              + * + * @param fieldName the field name + * @param obj the value to add to the toString + * @param fullDetail true for detail, + * false for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final Object obj, final boolean fullDetail) { + style.append(buffer, fieldName, obj, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString an Object + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final Object[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString an Object + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final Object[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Append to the toString an short + * value.

              + * + * @param fieldName the field name + * @param value the value to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final short value) { + style.append(buffer, fieldName, value); + return this; + } + + /** + *

              Append to the toString a short + * array.

              + * + * @param fieldName the field name + * @param array the array to add to the toString + * @return this + */ + public ToStringBuilder append(final String fieldName, final short[] array) { + style.append(buffer, fieldName, array, null); + return this; + } + + /** + *

              Append to the toString a short + * array.

              + * + *

              A boolean parameter controls the level of detail to show. + * Setting true will output the array in full. Setting + * false will output a summary, typically the size of + * the array. + * + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info + * @return this + */ + public ToStringBuilder append(final String fieldName, final short[] array, final boolean fullDetail) { + style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail)); + return this; + } + + /** + *

              Appends with the same format as the default Object toString() + * method. Appends the class name followed by + * {@link System#identityHashCode(java.lang.Object)}.

              + * + * @param srcObject the Object whose class name and id to output + * @return this + * @since 2.0 + */ + public ToStringBuilder appendAsObjectToString(final Object srcObject) { + ObjectUtils.identityToString(this.getStringBuffer(), srcObject); + return this; + } + + //---------------------------------------------------------------------------- + + /** + *

              Append the toString from the superclass.

              + * + *

              This method assumes that the superclass uses the same ToStringStyle + * as this one.

              + * + *

              If superToString is null, no change is made.

              + * + * @param superToString the result of super.toString() + * @return this + * @since 2.0 + */ + public ToStringBuilder appendSuper(final String superToString) { + if (superToString != null) { + style.appendSuper(buffer, superToString); + } + return this; + } + + /** + *

              Append the toString from another object.

              + * + *

              This method is useful where a class delegates most of the implementation of + * its properties to another class. You can then call toString() on + * the other class and pass the result into this method.

              + * + *
              +     *   private AnotherObject delegate;
              +     *   private String fieldInThisClass;
              +     *
              +     *   public String toString() {
              +     *     return new ToStringBuilder(this).
              +     *       appendToString(delegate.toString()).
              +     *       append(fieldInThisClass).
              +     *       toString();
              +     *   }
              + * + *

              This method assumes that the other object uses the same ToStringStyle + * as this one.

              + * + *

              If the toString is null, no change is made.

              + * + * @param toString the result of toString() on another object + * @return this + * @since 2.0 + */ + public ToStringBuilder appendToString(final String toString) { + if (toString != null) { + style.appendToString(buffer, toString); + } + return this; + } + + /** + *

              Returns the Object being output.

              + * + * @return The object being output. + * @since 2.0 + */ + public Object getObject() { + return object; + } + + /** + *

              Gets the StringBuffer being populated.

              + * + * @return the StringBuffer being populated + */ + public StringBuffer getStringBuffer() { + return buffer; + } + + //---------------------------------------------------------------------------- + + /** + *

              Gets the ToStringStyle being used.

              + * + * @return the ToStringStyle being used + * @since 2.0 + */ + public ToStringStyle getStyle() { + return style; + } + + /** + *

              Returns the built toString.

              + * + *

              This method appends the end of data indicator, and can only be called once. + * Use {@link #getStringBuffer} to get the current string state.

              + * + *

              If the object is null, return the style's nullText

              + * + * @return the String toString + */ + @Override + public String toString() { + if (this.getObject() == null) { + this.getStringBuffer().append(this.getStyle().getNullText()); + } else { + style.appendEnd(this.getStringBuffer(), this.getObject()); + } + return this.getStringBuffer().toString(); + } + + /** + * Returns the String that was build as an object representation. The + * default implementation utilizes the {@link #toString()} implementation. + * + * @return the String toString + * + * @see #toString() + * + * @since 3.0 + */ + @Override + public String build() { + return toString(); + } +} diff --git a/src/org/apache/commons/lang3/builder/ToStringExclude.java b/src/org/apache/commons/lang3/builder/ToStringExclude.java new file mode 100644 index 0000000..4cd31cc --- /dev/null +++ b/src/org/apache/commons/lang3/builder/ToStringExclude.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.builder; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.lang.annotation.RetentionPolicy; + +/** + * Use this annotation to exclude a field from being being used by + * the {@link ReflectionToStringBuilder}. + * + * @since 3.5 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ToStringExclude { + +} diff --git a/src/org/apache/commons/lang3/builder/ToStringStyle.java b/src/org/apache/commons/lang3/builder/ToStringStyle.java new file mode 100644 index 0000000..645525e --- /dev/null +++ b/src/org/apache/commons/lang3/builder/ToStringStyle.java @@ -0,0 +1,2637 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.builder; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Map; +import java.util.WeakHashMap; + +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; + +/** + *

              Controls String formatting for {@link ToStringBuilder}. + * The main public interface is always via ToStringBuilder.

              + * + *

              These classes are intended to be used as Singletons. + * There is no need to instantiate a new style each time. A program + * will generally use one of the predefined constants on this class. + * Alternatively, the {@link StandardToStringStyle} class can be used + * to set the individual settings. Thus most styles can be achieved + * without subclassing.

              + * + *

              If required, a subclass can override as many or as few of the + * methods as it requires. Each object type (from boolean + * to long to Object to int[]) has + * its own methods to output it. Most have two versions, detail and summary. + * + *

              For example, the detail version of the array based methods will + * output the whole array, whereas the summary method will just output + * the array length.

              + * + *

              If you want to format the output of certain objects, such as dates, you + * must create a subclass and override a method. + *

              + *
              + * public class MyStyle extends ToStringStyle {
              + *   protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
              + *     if (value instanceof Date) {
              + *       value = new SimpleDateFormat("yyyy-MM-dd").format(value);
              + *     }
              + *     buffer.append(value);
              + *   }
              + * }
              + * 
              + * + * @since 1.0 + */ +public abstract class ToStringStyle implements Serializable { + + /** + * Serialization version ID. + */ + private static final long serialVersionUID = -2587890625525655916L; + + /** + * The default toString style. Using the Person + * example from {@link ToStringBuilder}, the output would look like this: + * + *
              +     * Person@182f0db[name=John Doe,age=33,smoker=false]
              +     * 
              + */ + public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle(); + + /** + * The multi line toString style. Using the Person + * example from {@link ToStringBuilder}, the output would look like this: + * + *
              +     * Person@182f0db[
              +     *   name=John Doe
              +     *   age=33
              +     *   smoker=false
              +     * ]
              +     * 
              + */ + public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle(); + + /** + * The no field names toString style. Using the + * Person example from {@link ToStringBuilder}, the output + * would look like this: + * + *
              +     * Person@182f0db[John Doe,33,false]
              +     * 
              + */ + public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle(); + + /** + * The short prefix toString style. Using the Person example + * from {@link ToStringBuilder}, the output would look like this: + * + *
              +     * Person[name=John Doe,age=33,smoker=false]
              +     * 
              + * + * @since 2.1 + */ + public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle(); + + /** + * The simple toString style. Using the Person + * example from {@link ToStringBuilder}, the output would look like this: + * + *
              +     * John Doe,33,false
              +     * 
              + */ + public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle(); + + /** + * The no class name toString style. Using the Person + * example from {@link ToStringBuilder}, the output would look like this: + * + *
              +     * [name=John Doe,age=33,smoker=false]
              +     * 
              + * + * @since 3.4 + */ + public static final ToStringStyle NO_CLASS_NAME_STYLE = new NoClassNameToStringStyle(); + + /** + * The JSON toString style. Using the Person example from + * {@link ToStringBuilder}, the output would look like this: + * + *
              +     * {"name": "John Doe", "age": 33, "smoker": true}
              +     * 
              + * + * Note: Since field names are mandatory in JSON, this + * ToStringStyle will throw an {@link UnsupportedOperationException} if no + * field name is passed in while appending. Furthermore This ToStringStyle + * will only generate valid JSON if referenced objects also produce JSON + * when calling {@code toString()} on them. + * + * @since 3.4 + * @see json.org + */ + public static final ToStringStyle JSON_STYLE = new JsonToStringStyle(); + + /** + *

              + * A registry of objects used by reflectionToString methods + * to detect cyclical object references and avoid infinite loops. + *

              + */ + private static final ThreadLocal> REGISTRY = + new ThreadLocal<>(); + /* + * Note that objects of this class are generally shared between threads, so + * an instance variable would not be suitable here. + * + * In normal use the registry should always be left empty, because the caller + * should call toString() which will clean up. + * + * See LANG-792 + */ + + /** + *

              + * Returns the registry of objects being traversed by the reflectionToString + * methods in the current thread. + *

              + * + * @return Set the registry of objects being traversed + */ + static Map getRegistry() { + return REGISTRY.get(); + } + + /** + *

              + * Returns true if the registry contains the given object. + * Used by the reflection methods to avoid infinite loops. + *

              + * + * @param value + * The object to lookup in the registry. + * @return boolean true if the registry contains the given + * object. + */ + static boolean isRegistered(final Object value) { + final Map m = getRegistry(); + return m != null && m.containsKey(value); + } + + /** + *

              + * Registers the given object. Used by the reflection methods to avoid + * infinite loops. + *

              + * + * @param value + * The object to register. + */ + static void register(final Object value) { + if (value != null) { + final Map m = getRegistry(); + if (m == null) { + REGISTRY.set(new WeakHashMap<>()); + } + getRegistry().put(value, null); + } + } + + /** + *

              + * Unregisters the given object. + *

              + * + *

              + * Used by the reflection methods to avoid infinite loops. + *

              + * + * @param value + * The object to unregister. + */ + static void unregister(final Object value) { + if (value != null) { + final Map m = getRegistry(); + if (m != null) { + m.remove(value); + if (m.isEmpty()) { + REGISTRY.remove(); + } + } + } + } + + /** + * Whether to use the field names, the default is true. + */ + private boolean useFieldNames = true; + + /** + * Whether to use the class name, the default is true. + */ + private boolean useClassName = true; + + /** + * Whether to use short class names, the default is false. + */ + private boolean useShortClassName = false; + + /** + * Whether to use the identity hash code, the default is true. + */ + private boolean useIdentityHashCode = true; + + /** + * The content start '['. + */ + private String contentStart = "["; + + /** + * The content end ']'. + */ + private String contentEnd = "]"; + + /** + * The field name value separator '='. + */ + private String fieldNameValueSeparator = "="; + + /** + * Whether the field separator should be added before any other fields. + */ + private boolean fieldSeparatorAtStart = false; + + /** + * Whether the field separator should be added after any other fields. + */ + private boolean fieldSeparatorAtEnd = false; + + /** + * The field separator ','. + */ + private String fieldSeparator = ","; + + /** + * The array start '{'. + */ + private String arrayStart = "{"; + + /** + * The array separator ','. + */ + private String arraySeparator = ","; + + /** + * The detail for array content. + */ + private boolean arrayContentDetail = true; + + /** + * The array end '}'. + */ + private String arrayEnd = "}"; + + /** + * The value to use when fullDetail is null, + * the default value is true. + */ + private boolean defaultFullDetail = true; + + /** + * The null text '<null>'. + */ + private String nullText = ""; + + /** + * The summary size text start '<size'. + */ + private String sizeStartText = "'>'. + */ + private String sizeEndText = ">"; + + /** + * The summary object text start '<'. + */ + private String summaryObjectStartText = "<"; + + /** + * The summary object text start '>'. + */ + private String summaryObjectEndText = ">"; + + //---------------------------------------------------------------------------- + + /** + *

              Constructor.

              + */ + protected ToStringStyle() { + super(); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString the superclass toString.

              + *

              NOTE: It assumes that the toString has been created from the same ToStringStyle.

              + * + *

              A null superToString is ignored.

              + * + * @param buffer the StringBuffer to populate + * @param superToString the super.toString() + * @since 2.0 + */ + public void appendSuper(final StringBuffer buffer, final String superToString) { + appendToString(buffer, superToString); + } + + /** + *

              Append to the toString another toString.

              + *

              NOTE: It assumes that the toString has been created from the same ToStringStyle.

              + * + *

              A null toString is ignored.

              + * + * @param buffer the StringBuffer to populate + * @param toString the additional toString + * @since 2.0 + */ + public void appendToString(final StringBuffer buffer, final String toString) { + if (toString != null) { + final int pos1 = toString.indexOf(contentStart) + contentStart.length(); + final int pos2 = toString.lastIndexOf(contentEnd); + if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) { + final String data = toString.substring(pos1, pos2); + if (fieldSeparatorAtStart) { + removeLastFieldSeparator(buffer); + } + buffer.append(data); + appendFieldSeparator(buffer); + } + } + } + + /** + *

              Append to the toString the start of data indicator.

              + * + * @param buffer the StringBuffer to populate + * @param object the Object to build a toString for + */ + public void appendStart(final StringBuffer buffer, final Object object) { + if (object != null) { + appendClassName(buffer, object); + appendIdentityHashCode(buffer, object); + appendContentStart(buffer); + if (fieldSeparatorAtStart) { + appendFieldSeparator(buffer); + } + } + } + + /** + *

              Append to the toString the end of data indicator.

              + * + * @param buffer the StringBuffer to populate + * @param object the Object to build a + * toString for. + */ + public void appendEnd(final StringBuffer buffer, final Object object) { + if (this.fieldSeparatorAtEnd == false) { + removeLastFieldSeparator(buffer); + } + appendContentEnd(buffer); + unregister(object); + } + + /** + *

              Remove the last field separator from the buffer.

              + * + * @param buffer the StringBuffer to populate + * @since 2.0 + */ + protected void removeLastFieldSeparator(final StringBuffer buffer) { + final int len = buffer.length(); + final int sepLen = fieldSeparator.length(); + if (len > 0 && sepLen > 0 && len >= sepLen) { + boolean match = true; + for (int i = 0; i < sepLen; i++) { + if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) { + match = false; + break; + } + } + if (match) { + buffer.setLength(len - sepLen); + } + } + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString an Object + * value, printing the full toString of the + * Object passed in.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final Object value, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (value == null) { + appendNullText(buffer, fieldName); + + } else { + appendInternal(buffer, fieldName, value, isFullDetail(fullDetail)); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString an Object, + * correctly interpreting its type.

              + * + *

              This method performs the main lookup by Class type to correctly + * route arrays, Collections, Maps and + * Objects to the appropriate method.

              + * + *

              Either detail or summary views can be specified.

              + * + *

              If a cycle is detected, an object will be appended with the + * Object.toString() format.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString, + * not null + * @param detail output detail or not + */ + protected void appendInternal(final StringBuffer buffer, final String fieldName, final Object value, final boolean detail) { + if (isRegistered(value) + && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) { + appendCyclicObject(buffer, fieldName, value); + return; + } + + register(value); + + try { + if (value instanceof Collection) { + if (detail) { + appendDetail(buffer, fieldName, (Collection) value); + } else { + appendSummarySize(buffer, fieldName, ((Collection) value).size()); + } + + } else if (value instanceof Map) { + if (detail) { + appendDetail(buffer, fieldName, (Map) value); + } else { + appendSummarySize(buffer, fieldName, ((Map) value).size()); + } + + } else if (value instanceof long[]) { + if (detail) { + appendDetail(buffer, fieldName, (long[]) value); + } else { + appendSummary(buffer, fieldName, (long[]) value); + } + + } else if (value instanceof int[]) { + if (detail) { + appendDetail(buffer, fieldName, (int[]) value); + } else { + appendSummary(buffer, fieldName, (int[]) value); + } + + } else if (value instanceof short[]) { + if (detail) { + appendDetail(buffer, fieldName, (short[]) value); + } else { + appendSummary(buffer, fieldName, (short[]) value); + } + + } else if (value instanceof byte[]) { + if (detail) { + appendDetail(buffer, fieldName, (byte[]) value); + } else { + appendSummary(buffer, fieldName, (byte[]) value); + } + + } else if (value instanceof char[]) { + if (detail) { + appendDetail(buffer, fieldName, (char[]) value); + } else { + appendSummary(buffer, fieldName, (char[]) value); + } + + } else if (value instanceof double[]) { + if (detail) { + appendDetail(buffer, fieldName, (double[]) value); + } else { + appendSummary(buffer, fieldName, (double[]) value); + } + + } else if (value instanceof float[]) { + if (detail) { + appendDetail(buffer, fieldName, (float[]) value); + } else { + appendSummary(buffer, fieldName, (float[]) value); + } + + } else if (value instanceof boolean[]) { + if (detail) { + appendDetail(buffer, fieldName, (boolean[]) value); + } else { + appendSummary(buffer, fieldName, (boolean[]) value); + } + + } else if (value.getClass().isArray()) { + if (detail) { + appendDetail(buffer, fieldName, (Object[]) value); + } else { + appendSummary(buffer, fieldName, (Object[]) value); + } + + } else { + if (detail) { + appendDetail(buffer, fieldName, value); + } else { + appendSummary(buffer, fieldName, value); + } + } + } finally { + unregister(value); + } + } + + /** + *

              Append to the toString an Object + * value that has been detected to participate in a cycle. This + * implementation will print the standard string value of the value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString, + * not null + * + * @since 2.2 + */ + protected void appendCyclicObject(final StringBuffer buffer, final String fieldName, final Object value) { + ObjectUtils.identityToString(buffer, value); + } + + /** + *

              Append to the toString an Object + * value, printing the full detail of the Object.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { + buffer.append(value); + } + + /** + *

              Append to the toString a Collection.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param coll the Collection to add to the + * toString, not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection coll) { + buffer.append(coll); + } + + /** + *

              Append to the toString a Map.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param map the Map to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map map) { + buffer.append(map); + } + + /** + *

              Append to the toString an Object + * value, printing a summary of the Object.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object value) { + buffer.append(summaryObjectStartText); + buffer.append(getShortClassName(value.getClass())); + buffer.append(summaryObjectEndText); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a long + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final long value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString a long + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final long value) { + buffer.append(value); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString an int + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final int value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString an int + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final int value) { + buffer.append(value); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a short + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final short value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString a short + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final short value) { + buffer.append(value); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a byte + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final byte value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString a byte + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte value) { + buffer.append(value); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a char + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final char value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString a char + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) { + buffer.append(value); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a double + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final double value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString a double + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final double value) { + buffer.append(value); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a float + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final float value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString a float + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final float value) { + buffer.append(value); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a boolean + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param value the value to add to the toString + */ + public void append(final StringBuffer buffer, final String fieldName, final boolean value) { + appendFieldStart(buffer, fieldName); + appendDetail(buffer, fieldName, value); + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString a boolean + * value.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param value the value to add to the toString + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean value) { + buffer.append(value); + } + + /** + *

              Append to the toString an Object + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final Object[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString the detail of an + * Object array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + final Object item = array[i]; + if (i > 0) { + buffer.append(arraySeparator); + } + if (item == null) { + appendNullText(buffer, fieldName); + + } else { + appendInternal(buffer, fieldName, item, arrayContentDetail); + } + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString the detail of an array type.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + * @since 2.0 + */ + protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) { + buffer.append(arrayStart); + final int length = Array.getLength(array); + for (int i = 0; i < length; i++) { + final Object item = Array.get(array, i); + if (i > 0) { + buffer.append(arraySeparator); + } + if (item == null) { + appendNullText(buffer, fieldName); + + } else { + appendInternal(buffer, fieldName, item, arrayContentDetail); + } + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of an + * Object array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a long + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final long[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of a + * long array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of a + * long array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final long[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString an int + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final int[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of an + * int array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of an + * int array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final int[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a short + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final short[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of a + * short array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of a + * short array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final short[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a byte + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final byte[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of a + * byte array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of a + * byte array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final byte[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a char + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final char[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of a + * char array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of a + * char array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final char[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a double + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final double[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of a + * double array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of a + * double array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final double[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a float + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final float[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of a + * float array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of a + * float array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final float[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString a boolean + * array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + * @param array the array to add to the toString + * @param fullDetail true for detail, false + * for summary info, null for style decides + */ + public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, final Boolean fullDetail) { + appendFieldStart(buffer, fieldName); + + if (array == null) { + appendNullText(buffer, fieldName); + + } else if (isFullDetail(fullDetail)) { + appendDetail(buffer, fieldName, array); + + } else { + appendSummary(buffer, fieldName, array); + } + + appendFieldEnd(buffer, fieldName); + } + + /** + *

              Append to the toString the detail of a + * boolean array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) { + buffer.append(arrayStart); + for (int i = 0; i < array.length; i++) { + if (i > 0) { + buffer.append(arraySeparator); + } + appendDetail(buffer, fieldName, array[i]); + } + buffer.append(arrayEnd); + } + + /** + *

              Append to the toString a summary of a + * boolean array.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param array the array to add to the toString, + * not null + */ + protected void appendSummary(final StringBuffer buffer, final String fieldName, final boolean[] array) { + appendSummarySize(buffer, fieldName, array.length); + } + + //---------------------------------------------------------------------------- + + /** + *

              Append to the toString the class name.

              + * + * @param buffer the StringBuffer to populate + * @param object the Object whose name to output + */ + protected void appendClassName(final StringBuffer buffer, final Object object) { + if (useClassName && object != null) { + register(object); + if (useShortClassName) { + buffer.append(getShortClassName(object.getClass())); + } else { + buffer.append(object.getClass().getName()); + } + } + } + + /** + *

              Append the {@link System#identityHashCode(java.lang.Object)}.

              + * + * @param buffer the StringBuffer to populate + * @param object the Object whose id to output + */ + protected void appendIdentityHashCode(final StringBuffer buffer, final Object object) { + if (this.isUseIdentityHashCode() && object!=null) { + register(object); + buffer.append('@'); + buffer.append(Integer.toHexString(System.identityHashCode(object))); + } + } + + /** + *

              Append to the toString the content start.

              + * + * @param buffer the StringBuffer to populate + */ + protected void appendContentStart(final StringBuffer buffer) { + buffer.append(contentStart); + } + + /** + *

              Append to the toString the content end.

              + * + * @param buffer the StringBuffer to populate + */ + protected void appendContentEnd(final StringBuffer buffer) { + buffer.append(contentEnd); + } + + /** + *

              Append to the toString an indicator for null.

              + * + *

              The default indicator is '<null>'.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + */ + protected void appendNullText(final StringBuffer buffer, final String fieldName) { + buffer.append(nullText); + } + + /** + *

              Append to the toString the field separator.

              + * + * @param buffer the StringBuffer to populate + */ + protected void appendFieldSeparator(final StringBuffer buffer) { + buffer.append(fieldSeparator); + } + + /** + *

              Append to the toString the field start.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name + */ + protected void appendFieldStart(final StringBuffer buffer, final String fieldName) { + if (useFieldNames && fieldName != null) { + buffer.append(fieldName); + buffer.append(fieldNameValueSeparator); + } + } + + /** + *

              Append to the toString the field end.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + */ + protected void appendFieldEnd(final StringBuffer buffer, final String fieldName) { + appendFieldSeparator(buffer); + } + + /** + *

              Append to the toString a size summary.

              + * + *

              The size summary is used to summarize the contents of + * Collections, Maps and arrays.

              + * + *

              The output consists of a prefix, the passed in size + * and a suffix.

              + * + *

              The default format is '<size=n>'.

              + * + * @param buffer the StringBuffer to populate + * @param fieldName the field name, typically not used as already appended + * @param size the size to append + */ + protected void appendSummarySize(final StringBuffer buffer, final String fieldName, final int size) { + buffer.append(sizeStartText); + buffer.append(size); + buffer.append(sizeEndText); + } + + /** + *

              Is this field to be output in full detail.

              + * + *

              This method converts a detail request into a detail level. + * The calling code may request full detail (true), + * but a subclass might ignore that and always return + * false. The calling code may pass in + * null indicating that it doesn't care about + * the detail level. In this case the default detail level is + * used.

              + * + * @param fullDetailRequest the detail level requested + * @return whether full detail is to be shown + */ + protected boolean isFullDetail(final Boolean fullDetailRequest) { + if (fullDetailRequest == null) { + return defaultFullDetail; + } + return fullDetailRequest.booleanValue(); + } + + /** + *

              Gets the short class name for a class.

              + * + *

              The short class name is the classname excluding + * the package name.

              + * + * @param cls the Class to get the short name of + * @return the short name + */ + protected String getShortClassName(final Class cls) { + return ClassUtils.getShortClassName(cls); + } + + // Setters and getters for the customizable parts of the style + // These methods are not expected to be overridden, except to make public + // (They are not public so that immutable subclasses can be written) + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use the class name.

              + * + * @return the current useClassName flag + */ + protected boolean isUseClassName() { + return useClassName; + } + + /** + *

              Sets whether to use the class name.

              + * + * @param useClassName the new useClassName flag + */ + protected void setUseClassName(final boolean useClassName) { + this.useClassName = useClassName; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to output short or long class names.

              + * + * @return the current useShortClassName flag + * @since 2.0 + */ + protected boolean isUseShortClassName() { + return useShortClassName; + } + + /** + *

              Sets whether to output short or long class names.

              + * + * @param useShortClassName the new useShortClassName flag + * @since 2.0 + */ + protected void setUseShortClassName(final boolean useShortClassName) { + this.useShortClassName = useShortClassName; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use the identity hash code.

              + * + * @return the current useIdentityHashCode flag + */ + protected boolean isUseIdentityHashCode() { + return useIdentityHashCode; + } + + /** + *

              Sets whether to use the identity hash code.

              + * + * @param useIdentityHashCode the new useIdentityHashCode flag + */ + protected void setUseIdentityHashCode(final boolean useIdentityHashCode) { + this.useIdentityHashCode = useIdentityHashCode; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use the field names passed in.

              + * + * @return the current useFieldNames flag + */ + protected boolean isUseFieldNames() { + return useFieldNames; + } + + /** + *

              Sets whether to use the field names passed in.

              + * + * @param useFieldNames the new useFieldNames flag + */ + protected void setUseFieldNames(final boolean useFieldNames) { + this.useFieldNames = useFieldNames; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to use full detail when the caller doesn't + * specify.

              + * + * @return the current defaultFullDetail flag + */ + protected boolean isDefaultFullDetail() { + return defaultFullDetail; + } + + /** + *

              Sets whether to use full detail when the caller doesn't + * specify.

              + * + * @param defaultFullDetail the new defaultFullDetail flag + */ + protected void setDefaultFullDetail(final boolean defaultFullDetail) { + this.defaultFullDetail = defaultFullDetail; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether to output array content detail.

              + * + * @return the current array content detail setting + */ + protected boolean isArrayContentDetail() { + return arrayContentDetail; + } + + /** + *

              Sets whether to output array content detail.

              + * + * @param arrayContentDetail the new arrayContentDetail flag + */ + protected void setArrayContentDetail(final boolean arrayContentDetail) { + this.arrayContentDetail = arrayContentDetail; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the array start text.

              + * + * @return the current array start text + */ + protected String getArrayStart() { + return arrayStart; + } + + /** + *

              Sets the array start text.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param arrayStart the new array start text + */ + protected void setArrayStart(String arrayStart) { + if (arrayStart == null) { + arrayStart = StringUtils.EMPTY; + } + this.arrayStart = arrayStart; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the array end text.

              + * + * @return the current array end text + */ + protected String getArrayEnd() { + return arrayEnd; + } + + /** + *

              Sets the array end text.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param arrayEnd the new array end text + */ + protected void setArrayEnd(String arrayEnd) { + if (arrayEnd == null) { + arrayEnd = StringUtils.EMPTY; + } + this.arrayEnd = arrayEnd; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the array separator text.

              + * + * @return the current array separator text + */ + protected String getArraySeparator() { + return arraySeparator; + } + + /** + *

              Sets the array separator text.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param arraySeparator the new array separator text + */ + protected void setArraySeparator(String arraySeparator) { + if (arraySeparator == null) { + arraySeparator = StringUtils.EMPTY; + } + this.arraySeparator = arraySeparator; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the content start text.

              + * + * @return the current content start text + */ + protected String getContentStart() { + return contentStart; + } + + /** + *

              Sets the content start text.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param contentStart the new content start text + */ + protected void setContentStart(String contentStart) { + if (contentStart == null) { + contentStart = StringUtils.EMPTY; + } + this.contentStart = contentStart; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the content end text.

              + * + * @return the current content end text + */ + protected String getContentEnd() { + return contentEnd; + } + + /** + *

              Sets the content end text.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param contentEnd the new content end text + */ + protected void setContentEnd(String contentEnd) { + if (contentEnd == null) { + contentEnd = StringUtils.EMPTY; + } + this.contentEnd = contentEnd; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the field name value separator text.

              + * + * @return the current field name value separator text + */ + protected String getFieldNameValueSeparator() { + return fieldNameValueSeparator; + } + + /** + *

              Sets the field name value separator text.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param fieldNameValueSeparator the new field name value separator text + */ + protected void setFieldNameValueSeparator(String fieldNameValueSeparator) { + if (fieldNameValueSeparator == null) { + fieldNameValueSeparator = StringUtils.EMPTY; + } + this.fieldNameValueSeparator = fieldNameValueSeparator; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the field separator text.

              + * + * @return the current field separator text + */ + protected String getFieldSeparator() { + return fieldSeparator; + } + + /** + *

              Sets the field separator text.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param fieldSeparator the new field separator text + */ + protected void setFieldSeparator(String fieldSeparator) { + if (fieldSeparator == null) { + fieldSeparator = StringUtils.EMPTY; + } + this.fieldSeparator = fieldSeparator; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether the field separator should be added at the start + * of each buffer.

              + * + * @return the fieldSeparatorAtStart flag + * @since 2.0 + */ + protected boolean isFieldSeparatorAtStart() { + return fieldSeparatorAtStart; + } + + /** + *

              Sets whether the field separator should be added at the start + * of each buffer.

              + * + * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag + * @since 2.0 + */ + protected void setFieldSeparatorAtStart(final boolean fieldSeparatorAtStart) { + this.fieldSeparatorAtStart = fieldSeparatorAtStart; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets whether the field separator should be added at the end + * of each buffer.

              + * + * @return fieldSeparatorAtEnd flag + * @since 2.0 + */ + protected boolean isFieldSeparatorAtEnd() { + return fieldSeparatorAtEnd; + } + + /** + *

              Sets whether the field separator should be added at the end + * of each buffer.

              + * + * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag + * @since 2.0 + */ + protected void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) { + this.fieldSeparatorAtEnd = fieldSeparatorAtEnd; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the text to output when null found.

              + * + * @return the current text to output when null found + */ + protected String getNullText() { + return nullText; + } + + /** + *

              Sets the text to output when null found.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param nullText the new text to output when null found + */ + protected void setNullText(String nullText) { + if (nullText == null) { + nullText = StringUtils.EMPTY; + } + this.nullText = nullText; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the start text to output when a Collection, + * Map or array size is output.

              + * + *

              This is output before the size value.

              + * + * @return the current start of size text + */ + protected String getSizeStartText() { + return sizeStartText; + } + + /** + *

              Sets the start text to output when a Collection, + * Map or array size is output.

              + * + *

              This is output before the size value.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param sizeStartText the new start of size text + */ + protected void setSizeStartText(String sizeStartText) { + if (sizeStartText == null) { + sizeStartText = StringUtils.EMPTY; + } + this.sizeStartText = sizeStartText; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the end text to output when a Collection, + * Map or array size is output.

              + * + *

              This is output after the size value.

              + * + * @return the current end of size text + */ + protected String getSizeEndText() { + return sizeEndText; + } + + /** + *

              Sets the end text to output when a Collection, + * Map or array size is output.

              + * + *

              This is output after the size value.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param sizeEndText the new end of size text + */ + protected void setSizeEndText(String sizeEndText) { + if (sizeEndText == null) { + sizeEndText = StringUtils.EMPTY; + } + this.sizeEndText = sizeEndText; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the start text to output when an Object is + * output in summary mode.

              + * + *

              This is output before the size value.

              + * + * @return the current start of summary text + */ + protected String getSummaryObjectStartText() { + return summaryObjectStartText; + } + + /** + *

              Sets the start text to output when an Object is + * output in summary mode.

              + * + *

              This is output before the size value.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param summaryObjectStartText the new start of summary text + */ + protected void setSummaryObjectStartText(String summaryObjectStartText) { + if (summaryObjectStartText == null) { + summaryObjectStartText = StringUtils.EMPTY; + } + this.summaryObjectStartText = summaryObjectStartText; + } + + //--------------------------------------------------------------------- + + /** + *

              Gets the end text to output when an Object is + * output in summary mode.

              + * + *

              This is output after the size value.

              + * + * @return the current end of summary text + */ + protected String getSummaryObjectEndText() { + return summaryObjectEndText; + } + + /** + *

              Sets the end text to output when an Object is + * output in summary mode.

              + * + *

              This is output after the size value.

              + * + *

              null is accepted, but will be converted to + * an empty String.

              + * + * @param summaryObjectEndText the new end of summary text + */ + protected void setSummaryObjectEndText(String summaryObjectEndText) { + if (summaryObjectEndText == null) { + summaryObjectEndText = StringUtils.EMPTY; + } + this.summaryObjectEndText = summaryObjectEndText; + } + + //---------------------------------------------------------------------------- + + /** + *

              Default ToStringStyle.

              + * + *

              This is an inner class rather than using + * StandardToStringStyle to ensure its immutability.

              + */ + private static final class DefaultToStringStyle extends ToStringStyle { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + * + *

              Use the static constant rather than instantiating.

              + */ + DefaultToStringStyle() { + super(); + } + + /** + *

              Ensure Singleton after serialization.

              + * + * @return the singleton + */ + private Object readResolve() { + return ToStringStyle.DEFAULT_STYLE; + } + + } + + //---------------------------------------------------------------------------- + + /** + *

              ToStringStyle that does not print out + * the field names.

              + * + *

              This is an inner class rather than using + * StandardToStringStyle to ensure its immutability. + */ + private static final class NoFieldNameToStringStyle extends ToStringStyle { + + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + * + *

              Use the static constant rather than instantiating.

              + */ + NoFieldNameToStringStyle() { + super(); + this.setUseFieldNames(false); + } + + /** + *

              Ensure Singleton after serialization.

              + * + * @return the singleton + */ + private Object readResolve() { + return ToStringStyle.NO_FIELD_NAMES_STYLE; + } + + } + + //---------------------------------------------------------------------------- + + /** + *

              ToStringStyle that prints out the short + * class name and no identity hashcode.

              + * + *

              This is an inner class rather than using + * StandardToStringStyle to ensure its immutability.

              + */ + private static final class ShortPrefixToStringStyle extends ToStringStyle { + + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + * + *

              Use the static constant rather than instantiating.

              + */ + ShortPrefixToStringStyle() { + super(); + this.setUseShortClassName(true); + this.setUseIdentityHashCode(false); + } + + /** + *

              Ensure Singleton after serialization.

              + * @return the singleton + */ + private Object readResolve() { + return ToStringStyle.SHORT_PREFIX_STYLE; + } + + } + + //---------------------------------------------------------------------------- + + /** + *

              ToStringStyle that does not print out the + * classname, identity hashcode, content start or field name.

              + * + *

              This is an inner class rather than using + * StandardToStringStyle to ensure its immutability.

              + */ + private static final class SimpleToStringStyle extends ToStringStyle { + + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + * + *

              Use the static constant rather than instantiating.

              + */ + SimpleToStringStyle() { + super(); + this.setUseClassName(false); + this.setUseIdentityHashCode(false); + this.setUseFieldNames(false); + this.setContentStart(StringUtils.EMPTY); + this.setContentEnd(StringUtils.EMPTY); + } + + /** + *

              Ensure Singleton after serialization.

              + * @return the singleton + */ + private Object readResolve() { + return ToStringStyle.SIMPLE_STYLE; + } + + } + + //---------------------------------------------------------------------------- + + /** + *

              ToStringStyle that outputs on multiple lines.

              + * + *

              This is an inner class rather than using + * StandardToStringStyle to ensure its immutability.

              + */ + private static final class MultiLineToStringStyle extends ToStringStyle { + + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + * + *

              Use the static constant rather than instantiating.

              + */ + MultiLineToStringStyle() { + super(); + this.setContentStart("["); + this.setFieldSeparator(System.lineSeparator() + " "); + this.setFieldSeparatorAtStart(true); + this.setContentEnd(System.lineSeparator() + "]"); + } + + /** + *

              Ensure Singleton after serialization.

              + * + * @return the singleton + */ + private Object readResolve() { + return ToStringStyle.MULTI_LINE_STYLE; + } + + } + + //---------------------------------------------------------------------------- + + /** + *

              ToStringStyle that does not print out the classname + * and identity hash code but prints content start and field names.

              + * + *

              This is an inner class rather than using + * StandardToStringStyle to ensure its immutability.

              + */ + private static final class NoClassNameToStringStyle extends ToStringStyle { + + private static final long serialVersionUID = 1L; + + /** + *

              Constructor.

              + * + *

              Use the static constant rather than instantiating.

              + */ + NoClassNameToStringStyle() { + super(); + this.setUseClassName(false); + this.setUseIdentityHashCode(false); + } + + /** + *

              Ensure Singleton after serialization.

              + * + * @return the singleton + */ + private Object readResolve() { + return ToStringStyle.NO_CLASS_NAME_STYLE; + } + + } + + // ---------------------------------------------------------------------------- + + /** + *

              + * ToStringStyle that outputs with JSON format. + *

              + * + *

              + * This is an inner class rather than using + * StandardToStringStyle to ensure its immutability. + *

              + * + * @since 3.4 + * @see json.org + */ + private static final class JsonToStringStyle extends ToStringStyle { + + private static final long serialVersionUID = 1L; + + private static final String FIELD_NAME_QUOTE = "\""; + + /** + *

              + * Constructor. + *

              + * + *

              + * Use the static constant rather than instantiating. + *

              + */ + JsonToStringStyle() { + super(); + + this.setUseClassName(false); + this.setUseIdentityHashCode(false); + + this.setContentStart("{"); + this.setContentEnd("}"); + + this.setArrayStart("["); + this.setArrayEnd("]"); + + this.setFieldSeparator(","); + this.setFieldNameValueSeparator(":"); + + this.setNullText("null"); + + this.setSummaryObjectStartText("\"<"); + this.setSummaryObjectEndText(">\""); + + this.setSizeStartText("\"\""); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, + final Object[] array, final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, final long[] array, + final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, final int[] array, + final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, + final short[] array, final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, final byte[] array, + final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, final char[] array, + final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, + final double[] array, final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, + final float[] array, final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, + final boolean[] array, final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, array, fullDetail); + } + + @Override + public void append(final StringBuffer buffer, final String fieldName, final Object value, + final Boolean fullDetail) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + if (!isFullDetail(fullDetail)){ + throw new UnsupportedOperationException( + "FullDetail must be true when using JsonToStringStyle"); + } + + super.append(buffer, fieldName, value, fullDetail); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) { + appendValueAsString(buffer, String.valueOf(value)); + } + + @Override + protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) { + + if (value == null) { + appendNullText(buffer, fieldName); + return; + } + + if (value instanceof String || value instanceof Character) { + appendValueAsString(buffer, value.toString()); + return; + } + + if (value instanceof Number || value instanceof Boolean) { + buffer.append(value); + return; + } + + final String valueAsString = value.toString(); + if (isJsonObject(valueAsString) || isJsonArray(valueAsString)) { + buffer.append(value); + return; + } + + appendDetail(buffer, fieldName, valueAsString); + } + + private boolean isJsonArray(final String valueAsString) { + return valueAsString.startsWith(getArrayStart()) + && valueAsString.startsWith(getArrayEnd()); + } + + private boolean isJsonObject(final String valueAsString) { + return valueAsString.startsWith(getContentStart()) + && valueAsString.endsWith(getContentEnd()); + } + + /** + * Appends the given String in parenthesis to the given StringBuffer. + * + * @param buffer the StringBuffer to append the value to. + * @param value the value to append. + */ + private void appendValueAsString(final StringBuffer buffer, final String value) { + buffer.append("\"" + value + "\""); + } + + @Override + protected void appendFieldStart(final StringBuffer buffer, final String fieldName) { + + if (fieldName == null) { + throw new UnsupportedOperationException( + "Field names are mandatory when using JsonToStringStyle"); + } + + super.appendFieldStart(buffer, FIELD_NAME_QUOTE + fieldName + + FIELD_NAME_QUOTE); + } + + /** + *

              + * Ensure Singleton after serialization. + *

              + * + * @return the singleton + */ + private Object readResolve() { + return ToStringStyle.JSON_STYLE; + } + + } +} diff --git a/src/org/apache/commons/lang3/builder/package-info.java b/src/org/apache/commons/lang3/builder/package-info.java new file mode 100644 index 0000000..0043587 --- /dev/null +++ b/src/org/apache/commons/lang3/builder/package-info.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Assists in creating consistent {@code equals(Object)}, {@code toString()}, {@code hashCode()}, and {@code compareTo(Object)} methods. + * These classes are not thread-safe.

              + * + *

              When you write a {@link java.lang.Object#hashCode() hashCode()}, do you check Bloch's Effective Java? No? + * You just hack in a quick number? + * Well {@link org.apache.commons.lang3.builder.HashCodeBuilder} will save your day. + * It, and its buddies ({@link org.apache.commons.lang3.builder.EqualsBuilder}, {@link org.apache.commons.lang3.builder.CompareToBuilder}, {@link org.apache.commons.lang3.builder.ToStringBuilder}), take care of the nasty bits while you focus on the important bits, like which fields will go into making up the hashcode.

              + * + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#toString() + * @see java.lang.Object#hashCode() + * @see java.lang.Comparable#compareTo(Object) + * + * @since 1.0 + */ +package org.apache.commons.lang3.builder; diff --git a/src/org/apache/commons/lang3/concurrent/AbstractCircuitBreaker.java b/src/org/apache/commons/lang3/concurrent/AbstractCircuitBreaker.java new file mode 100644 index 0000000..6eeade0 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/AbstractCircuitBreaker.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Base class for circuit breakers. + * + * @param the type of the value monitored by this circuit breaker + * @since 3.5 + */ +public abstract class AbstractCircuitBreaker implements CircuitBreaker { + /** + * The name of the open property as it is passed to registered + * change listeners. + */ + public static final String PROPERTY_NAME = "open"; + + /** The current state of this circuit breaker. */ + protected final AtomicReference state = new AtomicReference<>(State.CLOSED); + + /** An object for managing change listeners registered at this instance. */ + private final PropertyChangeSupport changeSupport; + + /** + * Creates an {@code AbstractCircuitBreaker}. It also creates an internal {@code PropertyChangeSupport}. + */ + public AbstractCircuitBreaker() { + changeSupport = new PropertyChangeSupport(this); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isOpen() { + return isOpen(state.get()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isClosed() { + return !isOpen(); + } + + /** + * {@inheritDoc} + */ + @Override + public abstract boolean checkState(); + + /** + * {@inheritDoc} + */ + @Override + public abstract boolean incrementAndCheckState(T increment); + + /** + * {@inheritDoc} + */ + @Override + public void close() { + changeState(State.CLOSED); + } + + /** + * {@inheritDoc} + */ + @Override + public void open() { + changeState(State.OPEN); + } + + /** + * Converts the given state value to a boolean open property. + * + * @param state the state to be converted + * @return the boolean open flag + */ + protected static boolean isOpen(final State state) { + return state == State.OPEN; + } + + /** + * Changes the internal state of this circuit breaker. If there is actually a change + * of the state value, all registered change listeners are notified. + * + * @param newState the new state to be set + */ + protected void changeState(final State newState) { + if (state.compareAndSet(newState.oppositeState(), newState)) { + changeSupport.firePropertyChange(PROPERTY_NAME, !isOpen(newState), isOpen(newState)); + } + } + + /** + * Adds a change listener to this circuit breaker. This listener is notified whenever + * the state of this circuit breaker changes. If the listener is + * null, it is silently ignored. + * + * @param listener the listener to be added + */ + public void addChangeListener(final PropertyChangeListener listener) { + changeSupport.addPropertyChangeListener(listener); + } + + /** + * Removes the specified change listener from this circuit breaker. + * + * @param listener the listener to be removed + */ + public void removeChangeListener(final PropertyChangeListener listener) { + changeSupport.removePropertyChangeListener(listener); + } + + /** + * An internal enumeration representing the different states of a circuit + * breaker. This class also contains some logic for performing state + * transitions. This is done to avoid complex if-conditions in the code of + * {@code CircuitBreaker}. + */ + protected static enum State { + CLOSED { + /** + * {@inheritDoc} + */ + @Override + public State oppositeState() { + return OPEN; + } + }, + + OPEN { + /** + * {@inheritDoc} + */ + @Override + public State oppositeState() { + return CLOSED; + } + }; + + /** + * Returns the opposite state to the represented state. This is useful + * for flipping the current state. + * + * @return the opposite state + */ + public abstract State oppositeState(); + } + +} diff --git a/src/org/apache/commons/lang3/concurrent/AtomicInitializer.java b/src/org/apache/commons/lang3/concurrent/AtomicInitializer.java new file mode 100644 index 0000000..ac4b85e --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/AtomicInitializer.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.atomic.AtomicReference; + +/** + *

              + * A specialized implementation of the {@code ConcurrentInitializer} interface + * based on an {@link AtomicReference} variable. + *

              + *

              + * This class maintains a member field of type {@code AtomicReference}. It + * implements the following algorithm to create and initialize an object in its + * {@link #get()} method: + *

              + *
                + *
              • First it is checked whether the {@code AtomicReference} variable contains + * already a value. If this is the case, the value is directly returned.
              • + *
              • Otherwise the {@link #initialize()} method is called. This method must be + * defined in concrete subclasses to actually create the managed object.
              • + *
              • After the object was created by {@link #initialize()} it is checked + * whether the {@code AtomicReference} variable is still undefined. This has to + * be done because in the meantime another thread may have initialized the + * object. If the reference is still empty, the newly created object is stored + * in it and returned by this method.
              • + *
              • Otherwise the value stored in the {@code AtomicReference} is returned.
              • + *
              + *

              + * Because atomic variables are used this class does not need any + * synchronization. So there is no danger of deadlock, and access to the managed + * object is efficient. However, if multiple threads access the {@code + * AtomicInitializer} object before it has been initialized almost at the same + * time, it can happen that {@link #initialize()} is called multiple times. The + * algorithm outlined above guarantees that {@link #get()} always returns the + * same object though. + *

              + *

              + * Compared with the {@link LazyInitializer} class, this class can be more + * efficient because it does not need synchronization. The drawback is that the + * {@link #initialize()} method can be called multiple times which may be + * problematic if the creation of the managed object is expensive. As a rule of + * thumb this initializer implementation is preferable if there are not too many + * threads involved and the probability that multiple threads access an + * uninitialized object is small. If there is high parallelism, + * {@link LazyInitializer} is more appropriate. + *

              + * + * @since 3.0 + * @param the type of the object managed by this initializer class + */ +public abstract class AtomicInitializer implements ConcurrentInitializer { + /** Holds the reference to the managed object. */ + private final AtomicReference reference = new AtomicReference<>(); + + /** + * Returns the object managed by this initializer. The object is created if + * it is not available yet and stored internally. This method always returns + * the same object. + * + * @return the object created by this {@code AtomicInitializer} + * @throws ConcurrentException if an error occurred during initialization of + * the object + */ + @Override + public T get() throws ConcurrentException { + T result = reference.get(); + + if (result == null) { + result = initialize(); + if (!reference.compareAndSet(null, result)) { + // another thread has initialized the reference + result = reference.get(); + } + } + + return result; + } + + /** + * Creates and initializes the object managed by this {@code + * AtomicInitializer}. This method is called by {@link #get()} when the + * managed object is not available yet. An implementation can focus on the + * creation of the object. No synchronization is needed, as this is already + * handled by {@code get()}. As stated by the class comment, it is possible + * that this method is called multiple times. + * + * @return the managed data object + * @throws ConcurrentException if an error occurs during object creation + */ + protected abstract T initialize() throws ConcurrentException; +} diff --git a/src/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java b/src/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java new file mode 100644 index 0000000..0b1a500 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/AtomicSafeInitializer.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.atomic.AtomicReference; + +/** + *

              + * A specialized {@code ConcurrentInitializer} implementation which is similar + * to {@link AtomicInitializer}, but ensures that the {@link #initialize()} + * method is called only once. + *

              + *

              + * As {@link AtomicInitializer} this class is based on atomic variables, so it + * can create an object under concurrent access without synchronization. + * However, it implements an additional check to guarantee that the + * {@link #initialize()} method which actually creates the object cannot be + * called multiple times. + *

              + *

              + * Because of this additional check this implementation is slightly less + * efficient than {@link AtomicInitializer}, but if the object creation in the + * {@code initialize()} method is expensive or if multiple invocations of + * {@code initialize()} are problematic, it is the better alternative. + *

              + *

              + * From its semantics this class has the same properties as + * {@link LazyInitializer}. It is a "save" implementation of the lazy + * initializer pattern. Comparing both classes in terms of efficiency is + * difficult because which one is faster depends on multiple factors. Because + * {@code AtomicSafeInitializer} does not use synchronization at all it probably + * outruns {@link LazyInitializer}, at least under low or moderate concurrent + * access. Developers should run their own benchmarks on the expected target + * platform to decide which implementation is suitable for their specific use + * case. + *

              + * + * @since 3.0 + * @param the type of the object managed by this initializer class + */ +public abstract class AtomicSafeInitializer implements + ConcurrentInitializer { + /** A guard which ensures that initialize() is called only once. */ + private final AtomicReference> factory = + new AtomicReference<>(); + + /** Holds the reference to the managed object. */ + private final AtomicReference reference = new AtomicReference<>(); + + /** + * Get (and initialize, if not initialized yet) the required object + * + * @return lazily initialized object + * @throws ConcurrentException if the initialization of the object causes an + * exception + */ + @Override + public final T get() throws ConcurrentException { + T result; + + while ((result = reference.get()) == null) { + if (factory.compareAndSet(null, this)) { + reference.set(initialize()); + } + } + + return result; + } + + /** + * Creates and initializes the object managed by this + * {@code AtomicInitializer}. This method is called by {@link #get()} when + * the managed object is not available yet. An implementation can focus on + * the creation of the object. No synchronization is needed, as this is + * already handled by {@code get()}. This method is guaranteed to be called + * only once. + * + * @return the managed data object + * @throws ConcurrentException if an error occurs during object creation + */ + protected abstract T initialize() throws ConcurrentException; +} diff --git a/src/org/apache/commons/lang3/concurrent/BackgroundInitializer.java b/src/org/apache/commons/lang3/concurrent/BackgroundInitializer.java new file mode 100644 index 0000000..7b2662f --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/BackgroundInitializer.java @@ -0,0 +1,334 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + *

              + * A class that allows complex initialization operations in a background task. + *

              + *

              + * Applications often have to do some expensive initialization steps when they + * are started, e.g. constructing a connection to a database, reading a + * configuration file, etc. Doing these things in parallel can enhance + * performance as the CPU load can be improved. However, when access to the + * resources initialized in a background thread is actually required, + * synchronization has to be performed to ensure that their initialization is + * complete. + *

              + *

              + * This abstract base class provides support for this use case. A concrete + * subclass must implement the {@link #initialize()} method. Here an arbitrary + * initialization can be implemented, and a result object can be returned. With + * this method in place the basic usage of this class is as follows (where + * {@code MyBackgroundInitializer} is a concrete subclass): + *

              + * + *
              + * MyBackgroundInitializer initializer = new MyBackgroundInitializer();
              + * initializer.start();
              + * // Now do some other things. Initialization runs in a parallel thread
              + * ...
              + * // Wait for the end of initialization and access the result object
              + * Object result = initializer.get();
              + * 
              + * + *

              + * After the construction of a {@code BackgroundInitializer} object its + * {@link #start()} method has to be called. This starts the background + * processing. The application can now continue to do other things. When it + * needs access to the object produced by the {@code BackgroundInitializer} it + * calls its {@link #get()} method. If initialization is already complete, + * {@link #get()} returns the result object immediately. Otherwise it blocks + * until the result object is fully constructed. + *

              + *

              + * {@code BackgroundInitializer} is a thin wrapper around a {@code Future} + * object and uses an {@code ExecutorService} for running the background + * initialization task. It is possible to pass in an {@code ExecutorService} at + * construction time or set one using {@code setExternalExecutor()} before + * {@code start()} was called. Then this object is used to spawn the background + * task. If no {@code ExecutorService} has been provided, {@code + * BackgroundInitializer} creates a temporary {@code ExecutorService} and + * destroys it when initialization is complete. + *

              + *

              + * The methods provided by {@code BackgroundInitializer} provide for minimal + * interaction with the wrapped {@code Future} object. It is also possible to + * obtain the {@code Future} object directly. Then the enhanced functionality + * offered by {@code Future} can be used, e.g. to check whether the background + * operation is complete or to cancel the operation. + *

              + * + * @since 3.0 + * @param the type of the object managed by this initializer class + */ +public abstract class BackgroundInitializer implements + ConcurrentInitializer { + /** The external executor service for executing tasks. */ + private ExecutorService externalExecutor; // @GuardedBy("this") + + /** A reference to the executor service that is actually used. */ + private ExecutorService executor; // @GuardedBy("this") + + /** Stores the handle to the background task. */ + private Future future; // @GuardedBy("this") + + /** + * Creates a new instance of {@code BackgroundInitializer}. No external + * {@code ExecutorService} is used. + */ + protected BackgroundInitializer() { + this(null); + } + + /** + * Creates a new instance of {@code BackgroundInitializer} and initializes + * it with the given {@code ExecutorService}. If the {@code ExecutorService} + * is not null, the background task for initializing this object will be + * scheduled at this service. Otherwise a new temporary {@code + * ExecutorService} is created. + * + * @param exec an external {@code ExecutorService} to be used for task + * execution + */ + protected BackgroundInitializer(final ExecutorService exec) { + setExternalExecutor(exec); + } + + /** + * Returns the external {@code ExecutorService} to be used by this class. + * + * @return the {@code ExecutorService} + */ + public final synchronized ExecutorService getExternalExecutor() { + return externalExecutor; + } + + /** + * Returns a flag whether this {@code BackgroundInitializer} has already + * been started. + * + * @return a flag whether the {@link #start()} method has already been + * called + */ + public synchronized boolean isStarted() { + return future != null; + } + + /** + * Sets an {@code ExecutorService} to be used by this class. The {@code + * ExecutorService} passed to this method is used for executing the + * background task. Thus it is possible to re-use an already existing + * {@code ExecutorService} or to use a specially configured one. If no + * {@code ExecutorService} is set, this instance creates a temporary one and + * destroys it after background initialization is complete. Note that this + * method must be called before {@link #start()}; otherwise an exception is + * thrown. + * + * @param externalExecutor the {@code ExecutorService} to be used + * @throws IllegalStateException if this initializer has already been + * started + */ + public final synchronized void setExternalExecutor( + final ExecutorService externalExecutor) { + if (isStarted()) { + throw new IllegalStateException( + "Cannot set ExecutorService after start()!"); + } + + this.externalExecutor = externalExecutor; + } + + /** + * Starts the background initialization. With this method the initializer + * becomes active and invokes the {@link #initialize()} method in a + * background task. A {@code BackgroundInitializer} can be started exactly + * once. The return value of this method determines whether the start was + * successful: only the first invocation of this method returns true, + * following invocations will return false. + * + * @return a flag whether the initializer could be started successfully + */ + public synchronized boolean start() { + // Not yet started? + if (!isStarted()) { + + // Determine the executor to use and whether a temporary one has to + // be created + ExecutorService tempExec; + executor = getExternalExecutor(); + if (executor == null) { + executor = tempExec = createExecutor(); + } else { + tempExec = null; + } + + future = executor.submit(createTask(tempExec)); + + return true; + } + + return false; + } + + /** + * Returns the result of the background initialization. This method blocks + * until initialization is complete. If the background processing caused a + * runtime exception, it is directly thrown by this method. Checked + * exceptions, including {@code InterruptedException} are wrapped in a + * {@link ConcurrentException}. Calling this method before {@link #start()} + * was called causes an {@code IllegalStateException} exception to be + * thrown. + * + * @return the object produced by this initializer + * @throws ConcurrentException if a checked exception occurred during + * background processing + * @throws IllegalStateException if {@link #start()} has not been called + */ + @Override + public T get() throws ConcurrentException { + try { + return getFuture().get(); + } catch (final ExecutionException execex) { + ConcurrentUtils.handleCause(execex); + return null; // should not be reached + } catch (final InterruptedException iex) { + // reset interrupted state + Thread.currentThread().interrupt(); + throw new ConcurrentException(iex); + } + } + + /** + * Returns the {@code Future} object that was created when {@link #start()} + * was called. Therefore this method can only be called after {@code + * start()}. + * + * @return the {@code Future} object wrapped by this initializer + * @throws IllegalStateException if {@link #start()} has not been called + */ + public synchronized Future getFuture() { + if (future == null) { + throw new IllegalStateException("start() must be called first!"); + } + + return future; + } + + /** + * Returns the {@code ExecutorService} that is actually used for executing + * the background task. This method can be called after {@link #start()} + * (before {@code start()} it returns null). If an external executor + * was set, this is also the active executor. Otherwise this method returns + * the temporary executor that was created by this object. + * + * @return the {@code ExecutorService} for executing the background task + */ + protected synchronized final ExecutorService getActiveExecutor() { + return executor; + } + + /** + * Returns the number of background tasks to be created for this + * initializer. This information is evaluated when a temporary {@code + * ExecutorService} is created. This base implementation returns 1. Derived + * classes that do more complex background processing can override it. This + * method is called from a synchronized block by the {@link #start()} + * method. Therefore overriding methods should be careful with obtaining + * other locks and return as fast as possible. + * + * @return the number of background tasks required by this initializer + */ + protected int getTaskCount() { + return 1; + } + + /** + * Performs the initialization. This method is called in a background task + * when this {@code BackgroundInitializer} is started. It must be + * implemented by a concrete subclass. An implementation is free to perform + * arbitrary initialization. The object returned by this method can be + * queried using the {@link #get()} method. + * + * @return a result object + * @throws Exception if an error occurs + */ + protected abstract T initialize() throws Exception; + + /** + * Creates a task for the background initialization. The {@code Callable} + * object returned by this method is passed to the {@code ExecutorService}. + * This implementation returns a task that invokes the {@link #initialize()} + * method. If a temporary {@code ExecutorService} is used, it is destroyed + * at the end of the task. + * + * @param execDestroy the {@code ExecutorService} to be destroyed by the + * task + * @return a task for the background initialization + */ + private Callable createTask(final ExecutorService execDestroy) { + return new InitializationTask(execDestroy); + } + + /** + * Creates the {@code ExecutorService} to be used. This method is called if + * no {@code ExecutorService} was provided at construction time. + * + * @return the {@code ExecutorService} to be used + */ + private ExecutorService createExecutor() { + return Executors.newFixedThreadPool(getTaskCount()); + } + + private class InitializationTask implements Callable { + /** Stores the executor service to be destroyed at the end. */ + private final ExecutorService execFinally; + + /** + * Creates a new instance of {@code InitializationTask} and initializes + * it with the {@code ExecutorService} to be destroyed at the end. + * + * @param exec the {@code ExecutorService} + */ + public InitializationTask(final ExecutorService exec) { + execFinally = exec; + } + + /** + * Initiates initialization and returns the result. + * + * @return the result object + * @throws Exception if an error occurs + */ + @Override + public T call() throws Exception { + try { + return initialize(); + } finally { + if (execFinally != null) { + execFinally.shutdown(); + } + } + } + } +} diff --git a/src/org/apache/commons/lang3/concurrent/BasicThreadFactory.java b/src/org/apache/commons/lang3/concurrent/BasicThreadFactory.java new file mode 100644 index 0000000..9164cca --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/BasicThreadFactory.java @@ -0,0 +1,381 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; + +/** + *

              + * An implementation of the {@code ThreadFactory} interface that provides some + * configuration options for the threads it creates. + *

              + *

              + * A {@code ThreadFactory} is used for instance by an {@code ExecutorService} to + * create the threads it uses for executing tasks. In many cases users do not + * have to care about a {@code ThreadFactory} because the default one used by an + * {@code ExecutorService} will do. However, if there are special requirements + * for the threads, a custom {@code ThreadFactory} has to be created. + *

              + *

              + * This class provides some frequently needed configuration options for the + * threads it creates. These are the following: + *

              + *
                + *
              • A name pattern for the threads created by this factory can be specified. + * This is often useful if an application uses multiple executor services for + * different purposes. If the names of the threads used by these services have + * meaningful names, log output or exception traces can be much easier to read. + * Naming patterns are format strings as used by the {@code + * String.format()} method. The string can contain the place holder {@code %d} + * which will be replaced by the number of the current thread ({@code + * ThreadFactoryImpl} keeps a counter of the threads it has already created). + * For instance, the naming pattern {@code "My %d. worker thread"} will result + * in thread names like {@code "My 1. worker thread"}, {@code + * "My 2. worker thread"} and so on.
              • + *
              • A flag whether the threads created by this factory should be daemon + * threads. This can impact the exit behavior of the current Java application + * because the JVM shuts down if there are only daemon threads running.
              • + *
              • The priority of the thread. Here an integer value can be provided. The + * {@code java.lang.Thread} class defines constants for valid ranges of priority + * values.
              • + *
              • The {@code UncaughtExceptionHandler} for the thread. This handler is + * called if an uncaught exception occurs within the thread.
              • + *
              + *

              + * {@code BasicThreadFactory} wraps another thread factory which actually + * creates new threads. The configuration options are set on the threads created + * by the wrapped thread factory. On construction time the factory to be wrapped + * can be specified. If none is provided, a default {@code ThreadFactory} is + * used. + *

              + *

              + * Instances of {@code BasicThreadFactory} are not created directly, but the + * nested {@code Builder} class is used for this purpose. Using the builder only + * the configuration options an application is interested in need to be set. The + * following example shows how a {@code BasicThreadFactory} is created and + * installed in an {@code ExecutorService}: + *

              + * + *
              + * // Create a factory that produces daemon threads with a naming pattern and
              + * // a priority
              + * BasicThreadFactory factory = new BasicThreadFactory.Builder()
              + *     .namingPattern("workerthread-%d")
              + *     .daemon(true)
              + *     .priority(Thread.MAX_PRIORITY)
              + *     .build();
              + * // Create an executor service for single-threaded execution
              + * ExecutorService exec = Executors.newSingleThreadExecutor(factory);
              + * 
              + * + * @since 3.0 + */ +public class BasicThreadFactory implements ThreadFactory { + /** A counter for the threads created by this factory. */ + private final AtomicLong threadCounter; + + /** Stores the wrapped factory. */ + private final ThreadFactory wrappedFactory; + + /** Stores the uncaught exception handler. */ + private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler; + + /** Stores the naming pattern for newly created threads. */ + private final String namingPattern; + + /** Stores the priority. */ + private final Integer priority; + + /** Stores the daemon status flag. */ + private final Boolean daemonFlag; + + /** + * Creates a new instance of {@code ThreadFactoryImpl} and configures it + * from the specified {@code Builder} object. + * + * @param builder the {@code Builder} object + */ + private BasicThreadFactory(final Builder builder) { + if (builder.wrappedFactory == null) { + wrappedFactory = Executors.defaultThreadFactory(); + } else { + wrappedFactory = builder.wrappedFactory; + } + + namingPattern = builder.namingPattern; + priority = builder.priority; + daemonFlag = builder.daemonFlag; + uncaughtExceptionHandler = builder.exceptionHandler; + + threadCounter = new AtomicLong(); + } + + /** + * Returns the wrapped {@code ThreadFactory}. This factory is used for + * actually creating threads. This method never returns null. If no + * {@code ThreadFactory} was passed when this object was created, a default + * thread factory is returned. + * + * @return the wrapped {@code ThreadFactory} + */ + public final ThreadFactory getWrappedFactory() { + return wrappedFactory; + } + + /** + * Returns the naming pattern for naming newly created threads. Result can + * be null if no naming pattern was provided. + * + * @return the naming pattern + */ + public final String getNamingPattern() { + return namingPattern; + } + + /** + * Returns the daemon flag. This flag determines whether newly created + * threads should be daemon threads. If true, this factory object + * calls {@code setDaemon(true)} on the newly created threads. Result can be + * null if no daemon flag was provided at creation time. + * + * @return the daemon flag + */ + public final Boolean getDaemonFlag() { + return daemonFlag; + } + + /** + * Returns the priority of the threads created by this factory. Result can + * be null if no priority was specified. + * + * @return the priority for newly created threads + */ + public final Integer getPriority() { + return priority; + } + + /** + * Returns the {@code UncaughtExceptionHandler} for the threads created by + * this factory. Result can be null if no handler was provided. + * + * @return the {@code UncaughtExceptionHandler} + */ + public final Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { + return uncaughtExceptionHandler; + } + + /** + * Returns the number of threads this factory has already created. This + * class maintains an internal counter that is incremented each time the + * {@link #newThread(Runnable)} method is invoked. + * + * @return the number of threads created by this factory + */ + public long getThreadCount() { + return threadCounter.get(); + } + + /** + * Creates a new thread. This implementation delegates to the wrapped + * factory for creating the thread. Then, on the newly created thread the + * corresponding configuration options are set. + * + * @param r the {@code Runnable} to be executed by the new thread + * @return the newly created thread + */ + @Override + public Thread newThread(final Runnable r) { + final Thread t = getWrappedFactory().newThread(r); + initializeThread(t); + + return t; + } + + /** + * Initializes the specified thread. This method is called by + * {@link #newThread(Runnable)} after a new thread has been obtained from + * the wrapped thread factory. It initializes the thread according to the + * options set for this factory. + * + * @param t the thread to be initialized + */ + private void initializeThread(final Thread t) { + + if (getNamingPattern() != null) { + final Long count = Long.valueOf(threadCounter.incrementAndGet()); + t.setName(String.format(getNamingPattern(), count)); + } + + if (getUncaughtExceptionHandler() != null) { + t.setUncaughtExceptionHandler(getUncaughtExceptionHandler()); + } + + if (getPriority() != null) { + t.setPriority(getPriority().intValue()); + } + + if (getDaemonFlag() != null) { + t.setDaemon(getDaemonFlag().booleanValue()); + } + } + + /** + *

              + * A builder class for creating instances of {@code + * BasicThreadFactory}. + *

              + *

              + * Using this builder class instances of {@code BasicThreadFactory} can be + * created and initialized. The class provides methods that correspond to + * the configuration options supported by {@code BasicThreadFactory}. Method + * chaining is supported. Refer to the documentation of {@code + * BasicThreadFactory} for a usage example. + *

              + * + */ + public static class Builder + implements org.apache.commons.lang3.builder.Builder { + + /** The wrapped factory. */ + private ThreadFactory wrappedFactory; + + /** The uncaught exception handler. */ + private Thread.UncaughtExceptionHandler exceptionHandler; + + /** The naming pattern. */ + private String namingPattern; + + /** The priority. */ + private Integer priority; + + /** The daemon flag. */ + private Boolean daemonFlag; + + /** + * Sets the {@code ThreadFactory} to be wrapped by the new {@code + * BasicThreadFactory}. + * + * @param factory the wrapped {@code ThreadFactory} (must not be + * null) + * @return a reference to this {@code Builder} + * @throws NullPointerException if the passed in {@code ThreadFactory} + * is null + */ + public Builder wrappedFactory(final ThreadFactory factory) { + if (factory == null) { + throw new NullPointerException( + "Wrapped ThreadFactory must not be null!"); + } + + wrappedFactory = factory; + return this; + } + + /** + * Sets the naming pattern to be used by the new {@code + * BasicThreadFactory}. + * + * @param pattern the naming pattern (must not be null) + * @return a reference to this {@code Builder} + * @throws NullPointerException if the naming pattern is null + */ + public Builder namingPattern(final String pattern) { + if (pattern == null) { + throw new NullPointerException( + "Naming pattern must not be null!"); + } + + namingPattern = pattern; + return this; + } + + /** + * Sets the daemon flag for the new {@code BasicThreadFactory}. If this + * flag is set to true the new thread factory will create daemon + * threads. + * + * @param f the value of the daemon flag + * @return a reference to this {@code Builder} + */ + public Builder daemon(final boolean f) { + daemonFlag = Boolean.valueOf(f); + return this; + } + + /** + * Sets the priority for the threads created by the new {@code + * BasicThreadFactory}. + * + * @param prio the priority + * @return a reference to this {@code Builder} + */ + public Builder priority(final int prio) { + priority = Integer.valueOf(prio); + return this; + } + + /** + * Sets the uncaught exception handler for the threads created by the + * new {@code BasicThreadFactory}. + * + * @param handler the {@code UncaughtExceptionHandler} (must not be + * null) + * @return a reference to this {@code Builder} + * @throws NullPointerException if the exception handler is null + */ + public Builder uncaughtExceptionHandler( + final Thread.UncaughtExceptionHandler handler) { + if (handler == null) { + throw new NullPointerException( + "Uncaught exception handler must not be null!"); + } + + exceptionHandler = handler; + return this; + } + + /** + * Resets this builder. All configuration options are set to default + * values. Note: If the {@link #build()} method was called, it is not + * necessary to call {@code reset()} explicitly because this is done + * automatically. + */ + public void reset() { + wrappedFactory = null; + exceptionHandler = null; + namingPattern = null; + priority = null; + daemonFlag = null; + } + + /** + * Creates a new {@code BasicThreadFactory} with all configuration + * options that have been specified by calling methods on this builder. + * After creating the factory {@link #reset()} is called. + * + * @return the new {@code BasicThreadFactory} + */ + @Override + public BasicThreadFactory build() { + final BasicThreadFactory factory = new BasicThreadFactory(this); + reset(); + return factory; + } + } +} diff --git a/src/org/apache/commons/lang3/concurrent/CallableBackgroundInitializer.java b/src/org/apache/commons/lang3/concurrent/CallableBackgroundInitializer.java new file mode 100644 index 0000000..1941400 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/CallableBackgroundInitializer.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; + +/** + *

              + * A specialized {@link BackgroundInitializer} implementation that wraps a + * {@code Callable} object. + *

              + *

              + * An instance of this class is initialized with a {@code Callable} object when + * it is constructed. The implementation of the {@link #initialize()} method + * defined in the super class delegates to this {@code Callable} so that the + * {@code Callable} is executed in the background thread. + *

              + *

              + * The {@code java.util.concurrent.Callable} interface is a standard mechanism + * of the JDK to define tasks to be executed by another thread. The {@code + * CallableBackgroundInitializer} class allows combining this standard interface + * with the background initializer API. + *

              + *

              + * Usage of this class is very similar to the default usage pattern of the + * {@link BackgroundInitializer} class: Just create an instance and provide the + * {@code Callable} object to be executed, then call the initializer's + * {@link #start()} method. This causes the {@code Callable} to be executed in + * another thread. When the results of the {@code Callable} are needed the + * initializer's {@link #get()} method can be called (which may block until + * background execution is complete). The following code fragment shows a + * typical usage example: + *

              + * + *
              + * // a Callable that performs a complex computation
              + * Callable<Integer> computationCallable = new MyComputationCallable();
              + * // setup the background initializer
              + * CallableBackgroundInitializer<Integer> initializer =
              + *     new CallableBackgroundInitializer(computationCallable);
              + * initializer.start();
              + * // Now do some other things. Initialization runs in a parallel thread
              + * ...
              + * // Wait for the end of initialization and access the result
              + * Integer result = initializer.get();
              + * 
              + * + * + * @since 3.0 + * @param the type of the object managed by this initializer class + */ +public class CallableBackgroundInitializer extends BackgroundInitializer { + /** The Callable to be executed. */ + private final Callable callable; + + /** + * Creates a new instance of {@code CallableBackgroundInitializer} and sets + * the {@code Callable} to be executed in a background thread. + * + * @param call the {@code Callable} (must not be null) + * @throws IllegalArgumentException if the {@code Callable} is null + */ + public CallableBackgroundInitializer(final Callable call) { + checkCallable(call); + callable = call; + } + + /** + * Creates a new instance of {@code CallableBackgroundInitializer} and + * initializes it with the {@code Callable} to be executed in a background + * thread and the {@code ExecutorService} for managing the background + * execution. + * + * @param call the {@code Callable} (must not be null) + * @param exec an external {@code ExecutorService} to be used for task + * execution + * @throws IllegalArgumentException if the {@code Callable} is null + */ + public CallableBackgroundInitializer(final Callable call, final ExecutorService exec) { + super(exec); + checkCallable(call); + callable = call; + } + + /** + * Performs initialization in a background thread. This implementation + * delegates to the {@code Callable} passed at construction time of this + * object. + * + * @return the result of the initialization + * @throws Exception if an error occurs + */ + @Override + protected T initialize() throws Exception { + return callable.call(); + } + + /** + * Tests the passed in {@code Callable} and throws an exception if it is + * undefined. + * + * @param call the object to check + * @throws IllegalArgumentException if the {@code Callable} is null + */ + private void checkCallable(final Callable call) { + if (call == null) { + throw new IllegalArgumentException("Callable must not be null!"); + } + } +} diff --git a/src/org/apache/commons/lang3/concurrent/CircuitBreaker.java b/src/org/apache/commons/lang3/concurrent/CircuitBreaker.java new file mode 100644 index 0000000..7420e70 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/CircuitBreaker.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +/** + *

              + * An interface describing a Circuit Breaker component. + *

              + *

              + * A circuit breaker can be used to protect an application against unreliable + * services or unexpected load. It typically monitors a specific resource. As long as this + * resource works as expected, it stays in state closed, meaning that the + * resource can be used. If problems are encountered when using the resource, the circuit + * breaker can switch into state open; then access to this resource is + * prohibited. Depending on a concrete implementation, it is possible that the circuit + * breaker switches back to state closed when the resource becomes available + * again. + *

              + *

              + * This interface defines a generic protocol of a circuit breaker component. It should be + * sufficiently generic to be applied to multiple different use cases. + *

              + * + * @param the type of the value monitored by this circuit breaker + * @since 3.5 + */ +public interface CircuitBreaker { + /** + * Returns the current open state of this circuit breaker. A return value of + * true means that the circuit breaker is currently open indicating a + * problem in the monitored sub system. + * + * @return the current open state of this circuit breaker + */ + boolean isOpen(); + + /** + * Returns the current closed state of this circuit breaker. A return value of + * true means that the circuit breaker is currently closed. This + * means that everything is okay with the monitored sub system. + * + * @return the current closed state of this circuit breaker + */ + boolean isClosed(); + + /** + * Checks the state of this circuit breaker and changes it if necessary. The return + * value indicates whether the circuit breaker is now in state {@code CLOSED}; a value + * of true typically means that the current operation can continue. + * + * @return true if the circuit breaker is now closed; + * false otherwise + */ + boolean checkState(); + + /** + * Closes this circuit breaker. Its state is changed to closed. If this circuit + * breaker is already closed, this method has no effect. + */ + void close(); + + /** + * Opens this circuit breaker. Its state is changed to open. Depending on a concrete + * implementation, it may close itself again if the monitored sub system becomes + * available. If this circuit breaker is already open, this method has no effect. + */ + void open(); + + /** + * Increments the monitored value and performs a check of the current state of this + * circuit breaker. This method works like {@link #checkState()}, but the monitored + * value is incremented before the state check is performed. + * + * @param increment value to increment in the monitored value of the circuit breaker + * @return true if the circuit breaker is now closed; + * false otherwise + */ + boolean incrementAndCheckState(T increment); +} diff --git a/src/org/apache/commons/lang3/concurrent/CircuitBreakingException.java b/src/org/apache/commons/lang3/concurrent/CircuitBreakingException.java new file mode 100644 index 0000000..a3b6fdc --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/CircuitBreakingException.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +/** + *

              + * An exception class used for reporting runtime error conditions related to + * circuit breakers. + *

              + * @since 3.5 + */ +public class CircuitBreakingException extends RuntimeException { + /** + * The serial version UID. + */ + private static final long serialVersionUID = 1408176654686913340L; + + /** + * Creates a new, uninitialized instance of {@code CircuitBreakingException}. + */ + public CircuitBreakingException() { + super(); + } + + /** + * Creates a new instance of {@code CircuitBreakingException} and initializes it with the given message and cause. + * + * @param message the error message + * @param cause the cause of this exception + */ + public CircuitBreakingException(final String message, final Throwable cause) { + super(message, cause); + } + + /** + * Creates a new instance of {@code CircuitBreakingException} and initializes it with the given message. + * + * @param message the error message + */ + public CircuitBreakingException(final String message) { + super(message); + } + + /** + * Creates a new instance of {@code CircuitBreakingException} and initializes it with the given cause. + * + * @param cause the cause of this exception + */ + public CircuitBreakingException(final Throwable cause) { + super(cause); + } + +} diff --git a/src/org/apache/commons/lang3/concurrent/Computable.java b/src/org/apache/commons/lang3/concurrent/Computable.java new file mode 100644 index 0000000..6cb37aa --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/Computable.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +/** + *

              Definition of an interface for a wrapper around a calculation that takes a single parameter and returns a result.

              + * + *

              This interface allows for wrapping a calculation into a class so that it maybe passed around an application.

              + * + * @param the type of the input to the calculation + * @param the type of the output of the calculation + * + * @since 3.6 + */ +public interface Computable { + + /** + * This method carries out the given operation with the provided argument. + * + * @param arg + * the argument for the calculation + * @return the result of the calculation + * @throws InterruptedException + * thrown if the calculation is interrupted + */ + O compute(final I arg) throws InterruptedException; +} diff --git a/src/org/apache/commons/lang3/concurrent/ConcurrentException.java b/src/org/apache/commons/lang3/concurrent/ConcurrentException.java new file mode 100644 index 0000000..92c642c --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/ConcurrentException.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +/** + *

              + * An exception class used for reporting error conditions related to accessing + * data of background tasks. + *

              + *

              + * The purpose of this exception class is analogous to the default JDK exception + * class {@link java.util.concurrent.ExecutionException}, i.e. it wraps an + * exception that occurred during the execution of a task. However, in contrast + * to {@code ExecutionException}, it wraps only checked exceptions. Runtime + * exceptions are thrown directly. + *

              + * + * @since 3.0 + */ +public class ConcurrentException extends Exception { + /** + * The serial version UID. + */ + private static final long serialVersionUID = 6622707671812226130L; + + /** + * Creates a new, uninitialized instance of {@code ConcurrentException}. + */ + protected ConcurrentException() { + super(); + } + + /** + * Creates a new instance of {@code ConcurrentException} and initializes it + * with the given cause. + * + * @param cause the cause of this exception + * @throws IllegalArgumentException if the cause is not a checked exception + */ + public ConcurrentException(final Throwable cause) { + super(ConcurrentUtils.checkedException(cause)); + } + + /** + * Creates a new instance of {@code ConcurrentException} and initializes it + * with the given message and cause. + * + * @param msg the error message + * @param cause the cause of this exception + * @throws IllegalArgumentException if the cause is not a checked exception + */ + public ConcurrentException(final String msg, final Throwable cause) { + super(msg, ConcurrentUtils.checkedException(cause)); + } +} diff --git a/src/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java b/src/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java new file mode 100644 index 0000000..5532f74 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/ConcurrentInitializer.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +/** + *

              + * Definition of an interface for the thread-safe initialization of objects. + *

              + *

              + * The idea behind this interface is to provide access to an object in a + * thread-safe manner. A {@code ConcurrentInitializer} can be passed to multiple + * threads which can all access the object produced by the initializer. Through + * the {@link #get()} method the object can be queried. + *

              + *

              + * Concrete implementations of this interface will use different strategies for + * the creation of the managed object, e.g. lazy initialization or + * initialization in a background thread. This is completely transparent to + * client code, so it is possible to change the initialization strategy without + * affecting clients. + *

              + * + * @since 3.0 + * @param the type of the object managed by this initializer class + */ +public interface ConcurrentInitializer { + /** + * Returns the fully initialized object produced by this {@code + * ConcurrentInitializer}. A concrete implementation here returns the + * results of the initialization process. This method may block until + * results are available. Typically, once created the result object is + * always the same. + * + * @return the object created by this {@code ConcurrentException} + * @throws ConcurrentException if an error occurred during initialization of + * the object + */ + T get() throws ConcurrentException; +} diff --git a/src/org/apache/commons/lang3/concurrent/ConcurrentRuntimeException.java b/src/org/apache/commons/lang3/concurrent/ConcurrentRuntimeException.java new file mode 100644 index 0000000..87287d9 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/ConcurrentRuntimeException.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +/** + *

              + * An exception class used for reporting runtime error conditions related to + * accessing data of background tasks. + *

              + *

              + * This class is an analogue of the {@link ConcurrentException} exception class. + * However, it is a runtime exception and thus does not need explicit catch + * clauses. Some methods of {@link ConcurrentUtils} throw {@code + * ConcurrentRuntimeException} exceptions rather than + * {@link ConcurrentException} exceptions. They can be used by client code that + * does not want to be bothered with checked exceptions. + *

              + * + * @since 3.0 + */ +public class ConcurrentRuntimeException extends RuntimeException { + /** + * The serial version UID. + */ + private static final long serialVersionUID = -6582182735562919670L; + + /** + * Creates a new, uninitialized instance of {@code + * ConcurrentRuntimeException}. + */ + protected ConcurrentRuntimeException() { + super(); + } + + /** + * Creates a new instance of {@code ConcurrentRuntimeException} and + * initializes it with the given cause. + * + * @param cause the cause of this exception + * @throws IllegalArgumentException if the cause is not a checked exception + */ + public ConcurrentRuntimeException(final Throwable cause) { + super(ConcurrentUtils.checkedException(cause)); + } + + /** + * Creates a new instance of {@code ConcurrentRuntimeException} and + * initializes it with the given message and cause. + * + * @param msg the error message + * @param cause the cause of this exception + * @throws IllegalArgumentException if the cause is not a checked exception + */ + public ConcurrentRuntimeException(final String msg, final Throwable cause) { + super(msg, ConcurrentUtils.checkedException(cause)); + } +} diff --git a/src/org/apache/commons/lang3/concurrent/ConcurrentUtils.java b/src/org/apache/commons/lang3/concurrent/ConcurrentUtils.java new file mode 100644 index 0000000..d024524 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/ConcurrentUtils.java @@ -0,0 +1,392 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

              + * An utility class providing functionality related to the {@code + * java.util.concurrent} package. + *

              + * + * @since 3.0 + */ +public class ConcurrentUtils { + + /** + * Private constructor so that no instances can be created. This class + * contains only static utility methods. + */ + private ConcurrentUtils() { + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentException} with the checked cause if + * necessary. This method performs the following checks on the cause of the + * passed in exception: + *
                + *
              • If the passed in exception is null or the cause is + * null, this method returns null.
              • + *
              • If the cause is a runtime exception, it is directly thrown.
              • + *
              • If the cause is an error, it is directly thrown, too.
              • + *
              • In any other case the cause is a checked exception. The method then + * creates a {@link ConcurrentException}, initializes it with the cause, and + * returns it.
              • + *
              + * + * @param ex the exception to be processed + * @return a {@code ConcurrentException} with the checked cause + */ + public static ConcurrentException extractCause(final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentException(ex.getMessage(), ex.getCause()); + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentRuntimeException} with the checked cause if + * necessary. This method works exactly like + * {@link #extractCause(ExecutionException)}. The only difference is that + * the cause of the specified {@code ExecutionException} is extracted as a + * runtime exception. This is an alternative for client code that does not + * want to deal with checked exceptions. + * + * @param ex the exception to be processed + * @return a {@code ConcurrentRuntimeException} with the checked cause + */ + public static ConcurrentRuntimeException extractCauseUnchecked( + final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); + } + + /** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex the exception to be handled + * @throws ConcurrentException if the cause of the {@code + * ExecutionException} is a checked exception + */ + public static void handleCause(final ExecutionException ex) + throws ConcurrentException { + final ConcurrentException cex = extractCause(ex); + + if (cex != null) { + throw cex; + } + } + + /** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex the exception to be handled + * @throws ConcurrentRuntimeException if the cause of the {@code + * ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ + public static void handleCauseUnchecked(final ExecutionException ex) { + final ConcurrentRuntimeException crex = extractCauseUnchecked(ex); + + if (crex != null) { + throw crex; + } + } + + /** + * Tests whether the specified {@code Throwable} is a checked exception. If + * not, an exception is thrown. + * + * @param ex the {@code Throwable} to check + * @return a flag whether the passed in exception is a checked exception + * @throws IllegalArgumentException if the {@code Throwable} is not a + * checked exception + */ + static Throwable checkedException(final Throwable ex) { + Validate.isTrue(ex != null && !(ex instanceof RuntimeException) + && !(ex instanceof Error), "Not a checked exception: " + ex); + + return ex; + } + + /** + * Tests whether the cause of the specified {@code ExecutionException} + * should be thrown and does it if necessary. + * + * @param ex the exception in question + */ + private static void throwCause(final ExecutionException ex) { + if (ex.getCause() instanceof RuntimeException) { + throw (RuntimeException) ex.getCause(); + } + + if (ex.getCause() instanceof Error) { + throw (Error) ex.getCause(); + } + } + + //----------------------------------------------------------------------- + /** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code + * get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException if the {@code ConcurrentInitializer} throws + * an exception + */ + public static T initialize(final ConcurrentInitializer initializer) + throws ConcurrentException { + return initializer != null ? initializer.get() : null; + } + + /** + * Invokes the specified {@code ConcurrentInitializer} and transforms + * occurring exceptions to runtime exceptions. This method works like + * {@link #initialize(ConcurrentInitializer)}, but if the {@code + * ConcurrentInitializer} throws a {@link ConcurrentException}, it is + * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}. + * So client code does not have to deal with checked exceptions. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static T initializeUnchecked(final ConcurrentInitializer initializer) { + try { + return initialize(initializer); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

              + * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

              + * + *
              +     * if (!map.containsKey(key)) {
              +     *     map.put(key, value);
              +     *     return value;
              +     * } else {
              +     *     return map.get(key);
              +     * }
              +     * 
              + * + *

              + * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

              + *

              + * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

              + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param value the value to be added + * @return the value stored in the map after this operation + */ + public static V putIfAbsent(final ConcurrentMap map, final K key, final V value) { + if (map == null) { + return null; + } + + final V result = map.putIfAbsent(key, value); + return result != null ? result : value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException if the initializer throws an exception + */ + public static V createIfAbsent(final ConcurrentMap map, final K key, + final ConcurrentInitializer init) throws ConcurrentException { + if (map == null || init == null) { + return null; + } + + final V value = map.get(key); + if (value == null) { + return putIfAbsent(map, key, init.get()); + } + return value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not, suppressing checked exceptions. This method calls + * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it + * is caught and re-thrown as a {@link ConcurrentRuntimeException}. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static V createIfAbsentUnchecked(final ConcurrentMap map, + final K key, final ConcurrentInitializer init) { + try { + return createIfAbsent(map, key, init); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

              + * Gets an implementation of Future that is immediately done + * and returns the specified constant value. + *

              + *

              + * This can be useful to return a simple constant immediately from the + * concurrent processing, perhaps as part of avoiding nulls. + * A constant future can also be useful in testing. + *

              + * + * @param the type of the value used by this {@code Future} object + * @param value the constant value to return, may be null + * @return an instance of Future that will return the value, never null + */ + public static Future constantFuture(final T value) { + return new ConstantFuture<>(value); + } + + /** + * A specialized {@code Future} implementation which wraps a constant value. + * @param the type of the value wrapped by this class + */ + static final class ConstantFuture implements Future { + /** The constant value. */ + private final T value; + + /** + * Creates a new instance of {@code ConstantFuture} and initializes it + * with the constant value. + * + * @param value the value (may be null) + */ + ConstantFuture(final T value) { + this.value = value; + } + + /** + * {@inheritDoc} This implementation always returns true because + * the constant object managed by this {@code Future} implementation is + * always available. + */ + @Override + public boolean isDone() { + return true; + } + + /** + * {@inheritDoc} This implementation just returns the constant value. + */ + @Override + public T get() { + return value; + } + + /** + * {@inheritDoc} This implementation just returns the constant value; it + * does not block, therefore the timeout has no meaning. + */ + @Override + public T get(final long timeout, final TimeUnit unit) { + return value; + } + + /** + * {@inheritDoc} This implementation always returns false; there + * is no background process which could be cancelled. + */ + @Override + public boolean isCancelled() { + return false; + } + + /** + * {@inheritDoc} The cancel operation is not supported. This + * implementation always returns false. + */ + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + } + +} diff --git a/src/org/apache/commons/lang3/concurrent/ConstantInitializer.java b/src/org/apache/commons/lang3/concurrent/ConstantInitializer.java new file mode 100644 index 0000000..4c6bc3e --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/ConstantInitializer.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.Objects; + +/** + *

              + * A very simple implementation of the {@link ConcurrentInitializer} interface + * which always returns the same object. + *

              + *

              + * An instance of this class is passed a reference to an object when it is + * constructed. The {@link #get()} method just returns this object. No + * synchronization is required. + *

              + *

              + * This class is useful for instance for unit testing or in cases where a + * specific object has to be passed to an object which expects a + * {@link ConcurrentInitializer}. + *

              + * + * @since 3.0 + * @param the type of the object managed by this initializer + */ +public class ConstantInitializer implements ConcurrentInitializer { + /** Constant for the format of the string representation. */ + private static final String FMT_TO_STRING = "ConstantInitializer@%d [ object = %s ]"; + + /** Stores the managed object. */ + private final T object; + + /** + * Creates a new instance of {@code ConstantInitializer} and initializes it + * with the object to be managed. The {@code get()} method will always + * return the object passed here. This class does not place any restrictions + * on the object. It may be null, then {@code get()} will return + * null, too. + * + * @param obj the object to be managed by this initializer + */ + public ConstantInitializer(final T obj) { + object = obj; + } + + /** + * Directly returns the object that was passed to the constructor. This is + * the same object as returned by {@code get()}. However, this method does + * not declare that it throws an exception. + * + * @return the object managed by this initializer + */ + public final T getObject() { + return object; + } + + /** + * Returns the object managed by this initializer. This implementation just + * returns the object passed to the constructor. + * + * @return the object managed by this initializer + * @throws ConcurrentException if an error occurs + */ + @Override + public T get() throws ConcurrentException { + return getObject(); + } + + /** + * Returns a hash code for this object. This implementation returns the hash + * code of the managed object. + * + * @return a hash code for this object + */ + @Override + public int hashCode() { + return getObject() != null ? getObject().hashCode() : 0; + } + + /** + * Compares this object with another one. This implementation returns + * true if and only if the passed in object is an instance of + * {@code ConstantInitializer} which refers to an object equals to the + * object managed by this instance. + * + * @param obj the object to compare to + * @return a flag whether the objects are equal + */ + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ConstantInitializer)) { + return false; + } + + final ConstantInitializer c = (ConstantInitializer) obj; + return Objects.equals(getObject(), c.getObject()); + } + + /** + * Returns a string representation for this object. This string also + * contains a string representation of the object managed by this + * initializer. + * + * @return a string for this object + */ + @Override + public String toString() { + return String.format(FMT_TO_STRING, Integer.valueOf(System.identityHashCode(this)), + String.valueOf(getObject())); + } +} diff --git a/src/org/apache/commons/lang3/concurrent/EventCountCircuitBreaker.java b/src/org/apache/commons/lang3/concurrent/EventCountCircuitBreaker.java new file mode 100644 index 0000000..d33ff48 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/EventCountCircuitBreaker.java @@ -0,0 +1,568 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.EnumMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + *

              + * A simple implementation of the Circuit Breaker pattern + * that counts specific events. + *

              + *

              + * A circuit breaker can be used to protect an application against unreliable + * services or unexpected load. A newly created {@code EventCountCircuitBreaker} object is + * initially in state closed meaning that no problem has been detected. When the + * application encounters specific events (like errors or service timeouts), it tells the + * circuit breaker to increment an internal counter. If the number of events reported in a + * specific time interval exceeds a configurable threshold, the circuit breaker changes + * into state open. This means that there is a problem with the associated sub + * system; the application should no longer call it, but give it some time to settle down. + * The circuit breaker can be configured to switch back to closed state after a + * certain time frame if the number of events received goes below a threshold. + *

              + *

              + * When a {@code EventCountCircuitBreaker} object is constructed the following parameters + * can be provided: + *

              + *
                + *
              • A threshold for the number of events that causes a state transition to + * open state. If more events are received in the configured check interval, the + * circuit breaker switches to open state.
              • + *
              • The interval for checks whether the circuit breaker should open. So it is possible + * to specify something like "The circuit breaker should open if more than 10 errors are + * encountered in a minute."
              • + *
              • The same parameters can be specified for automatically closing the circuit breaker + * again, as in "If the number of requests goes down to 100 per minute, the circuit + * breaker should close itself again". Depending on the use case, it may make sense to use + * a slightly lower threshold for closing the circuit breaker than for opening it to avoid + * continuously flipping when the number of events received is close to the threshold.
              • + *
              + *

              + * This class supports the following typical use cases: + *

              + *

              + * Protecting against load peaks + *

              + *

              + * Imagine you have a server which can handle a certain number of requests per minute. + * Suddenly, the number of requests increases significantly - maybe because a connected + * partner system is going mad or due to a denial of service attack. A + * {@code EventCountCircuitBreaker} can be configured to stop the application from + * processing requests when a sudden peak load is detected and to start request processing + * again when things calm down. The following code fragment shows a typical example of + * such a scenario. Here the {@code EventCountCircuitBreaker} allows up to 1000 requests + * per minute before it interferes. When the load goes down again to 800 requests per + * second it switches back to state closed: + *

              + * + *
              + * EventCountCircuitBreaker breaker = new EventCountCircuitBreaker(1000, 1, TimeUnit.MINUTE, 800);
              + * ...
              + * public void handleRequest(Request request) {
              + *     if (breaker.incrementAndCheckState()) {
              + *         // actually handle this request
              + *     } else {
              + *         // do something else, e.g. send an error code
              + *     }
              + * }
              + * 
              + *

              + * Deal with an unreliable service + *

              + *

              + * In this scenario, an application uses an external service which may fail from time to + * time. If there are too many errors, the service is considered down and should not be + * called for a while. This can be achieved using the following pattern - in this concrete + * example we accept up to 5 errors in 2 minutes; if this limit is reached, the service is + * given a rest time of 10 minutes: + *

              + * + *
              + * EventCountCircuitBreaker breaker = new EventCountCircuitBreaker(5, 2, TimeUnit.MINUTE, 5, 10, TimeUnit.MINUTE);
              + * ...
              + * public void handleRequest(Request request) {
              + *     if (breaker.checkState()) {
              + *         try {
              + *             service.doSomething();
              + *         } catch (ServiceException ex) {
              + *             breaker.incrementAndCheckState();
              + *         }
              + *     } else {
              + *         // return an error code, use an alternative service, etc.
              + *     }
              + * }
              + * 
              + *

              + * In addition to automatic state transitions, the state of a circuit breaker can be + * changed manually using the methods {@link #open()} and {@link #close()}. It is also + * possible to register {@code PropertyChangeListener} objects that get notified whenever + * a state transition occurs. This is useful, for instance to directly react on a freshly + * detected error condition. + *

              + *

              + * Implementation notes: + *

              + *
                + *
              • This implementation uses non-blocking algorithms to update the internal counter and + * state. This should be pretty efficient if there is not too much contention.
              • + *
              • This implementation is not intended to operate as a high-precision timer in very + * short check intervals. It is deliberately kept simple to avoid complex and + * time-consuming state checks. It should work well in time intervals from a few seconds + * up to minutes and longer. If the intervals become too short, there might be race + * conditions causing spurious state transitions.
              • + *
              • The handling of check intervals is a bit simplistic. Therefore, there is no + * guarantee that the circuit breaker is triggered at a specific point in time; there may + * be some delay (less than a check interval).
              • + *
              + * @since 3.5 + */ +public class EventCountCircuitBreaker extends AbstractCircuitBreaker { + + /** A map for accessing the strategy objects for the different states. */ + private static final Map STRATEGY_MAP = createStrategyMap(); + + /** Stores information about the current check interval. */ + private final AtomicReference checkIntervalData; + + /** The threshold for opening the circuit breaker. */ + private final int openingThreshold; + + /** The time interval for opening the circuit breaker. */ + private final long openingInterval; + + /** The threshold for closing the circuit breaker. */ + private final int closingThreshold; + + /** The time interval for closing the circuit breaker. */ + private final long closingInterval; + + /** + * Creates a new instance of {@code EventCountCircuitBreaker} and initializes all properties for + * opening and closing it based on threshold values for events occurring in specific + * intervals. + * + * @param openingThreshold the threshold for opening the circuit breaker; if this + * number of events is received in the time span determined by the opening interval, + * the circuit breaker is opened + * @param openingInterval the interval for opening the circuit breaker + * @param openingUnit the {@code TimeUnit} defining the opening interval + * @param closingThreshold the threshold for closing the circuit breaker; if the + * number of events received in the time span determined by the closing interval goes + * below this threshold, the circuit breaker is closed again + * @param closingInterval the interval for closing the circuit breaker + * @param closingUnit the {@code TimeUnit} defining the closing interval + */ + public EventCountCircuitBreaker(final int openingThreshold, final long openingInterval, + final TimeUnit openingUnit, final int closingThreshold, final long closingInterval, + final TimeUnit closingUnit) { + super(); + checkIntervalData = new AtomicReference<>(new CheckIntervalData(0, 0)); + this.openingThreshold = openingThreshold; + this.openingInterval = openingUnit.toNanos(openingInterval); + this.closingThreshold = closingThreshold; + this.closingInterval = closingUnit.toNanos(closingInterval); + } + + /** + * Creates a new instance of {@code EventCountCircuitBreaker} with the same interval for opening + * and closing checks. + * + * @param openingThreshold the threshold for opening the circuit breaker; if this + * number of events is received in the time span determined by the check interval, the + * circuit breaker is opened + * @param checkInterval the check interval for opening or closing the circuit breaker + * @param checkUnit the {@code TimeUnit} defining the check interval + * @param closingThreshold the threshold for closing the circuit breaker; if the + * number of events received in the time span determined by the check interval goes + * below this threshold, the circuit breaker is closed again + */ + public EventCountCircuitBreaker(final int openingThreshold, final long checkInterval, final TimeUnit checkUnit, + final int closingThreshold) { + this(openingThreshold, checkInterval, checkUnit, closingThreshold, checkInterval, + checkUnit); + } + + /** + * Creates a new instance of {@code EventCountCircuitBreaker} which uses the same parameters for + * opening and closing checks. + * + * @param threshold the threshold for changing the status of the circuit breaker; if + * the number of events received in a check interval is greater than this value, the + * circuit breaker is opened; if it is lower than this value, it is closed again + * @param checkInterval the check interval for opening or closing the circuit breaker + * @param checkUnit the {@code TimeUnit} defining the check interval + */ + public EventCountCircuitBreaker(final int threshold, final long checkInterval, final TimeUnit checkUnit) { + this(threshold, checkInterval, checkUnit, threshold); + } + + /** + * Returns the threshold value for opening the circuit breaker. If this number of + * events is received in the time span determined by the opening interval, the circuit + * breaker is opened. + * + * @return the opening threshold + */ + public int getOpeningThreshold() { + return openingThreshold; + } + + /** + * Returns the interval (in nanoseconds) for checking for the opening threshold. + * + * @return the opening check interval + */ + public long getOpeningInterval() { + return openingInterval; + } + + /** + * Returns the threshold value for closing the circuit breaker. If the number of + * events received in the time span determined by the closing interval goes below this + * threshold, the circuit breaker is closed again. + * + * @return the closing threshold + */ + public int getClosingThreshold() { + return closingThreshold; + } + + /** + * Returns the interval (in nanoseconds) for checking for the closing threshold. + * + * @return the opening check interval + */ + public long getClosingInterval() { + return closingInterval; + } + + /** + * {@inheritDoc} This implementation checks the internal event counter against the + * threshold values and the check intervals. This may cause a state change of this + * circuit breaker. + */ + @Override + public boolean checkState() { + return performStateCheck(0); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean incrementAndCheckState(final Integer increment) + throws CircuitBreakingException { + return performStateCheck(1); + } + + /** + * Increments the monitored value by 1 and performs a check of the current state of this + * circuit breaker. This method works like {@link #checkState()}, but the monitored + * value is incremented before the state check is performed. + * + * @return true if the circuit breaker is now closed; + * false otherwise + */ + public boolean incrementAndCheckState() { + return incrementAndCheckState(1); + } + + /** + * {@inheritDoc} This circuit breaker may close itself again if the number of events + * received during a check interval goes below the closing threshold. If this circuit + * breaker is already open, this method has no effect, except that a new check + * interval is started. + */ + @Override + public void open() { + super.open(); + checkIntervalData.set(new CheckIntervalData(0, now())); + } + + /** + * {@inheritDoc} A new check interval is started. If too many events are received in + * this interval, the circuit breaker changes again to state open. If this circuit + * breaker is already closed, this method has no effect, except that a new check + * interval is started. + */ + @Override + public void close() { + super.close(); + checkIntervalData.set(new CheckIntervalData(0, now())); + } + + /** + * Actually checks the state of this circuit breaker and executes a state transition + * if necessary. + * + * @param increment the increment for the internal counter + * @return a flag whether the circuit breaker is now closed + */ + private boolean performStateCheck(final int increment) { + CheckIntervalData currentData; + CheckIntervalData nextData; + State currentState; + + do { + final long time = now(); + currentState = state.get(); + currentData = checkIntervalData.get(); + nextData = nextCheckIntervalData(increment, currentData, currentState, time); + } while (!updateCheckIntervalData(currentData, nextData)); + + // This might cause a race condition if other changes happen in between! + // Refer to the header comment! + if (stateStrategy(currentState).isStateTransition(this, currentData, nextData)) { + currentState = currentState.oppositeState(); + changeStateAndStartNewCheckInterval(currentState); + } + return !isOpen(currentState); + } + + /** + * Updates the {@code CheckIntervalData} object. The current data object is replaced + * by the one modified by the last check. The return value indicates whether this was + * successful. If it is false, another thread interfered, and the + * whole operation has to be redone. + * + * @param currentData the current check data object + * @param nextData the replacing check data object + * @return a flag whether the update was successful + */ + private boolean updateCheckIntervalData(final CheckIntervalData currentData, + final CheckIntervalData nextData) { + return currentData == nextData + || checkIntervalData.compareAndSet(currentData, nextData); + } + + /** + * Changes the state of this circuit breaker and also initializes a new + * {@code CheckIntervalData} object. + * + * @param newState the new state to be set + */ + private void changeStateAndStartNewCheckInterval(final State newState) { + changeState(newState); + checkIntervalData.set(new CheckIntervalData(0, now())); + } + + /** + * Calculates the next {@code CheckIntervalData} object based on the current data and + * the current state. The next data object takes the counter increment and the current + * time into account. + * + * @param increment the increment for the internal counter + * @param currentData the current check data object + * @param currentState the current state of the circuit breaker + * @param time the current time + * @return the updated {@code CheckIntervalData} object + */ + private CheckIntervalData nextCheckIntervalData(final int increment, + final CheckIntervalData currentData, final State currentState, final long time) { + CheckIntervalData nextData; + if (stateStrategy(currentState).isCheckIntervalFinished(this, currentData, time)) { + nextData = new CheckIntervalData(increment, time); + } else { + nextData = currentData.increment(increment); + } + return nextData; + } + + /** + * Returns the current time in nanoseconds. This method is used to obtain the current + * time. This is needed to calculate the check intervals correctly. + * + * @return the current time in nanoseconds + */ + long now() { + return System.nanoTime(); + } + + /** + * Returns the {@code StateStrategy} object responsible for the given state. + * + * @param state the state + * @return the corresponding {@code StateStrategy} + * @throws CircuitBreakingException if the strategy cannot be resolved + */ + private static StateStrategy stateStrategy(final State state) { + final StateStrategy strategy = STRATEGY_MAP.get(state); + return strategy; + } + + /** + * Creates the map with strategy objects. It allows access for a strategy for a given + * state. + * + * @return the strategy map + */ + private static Map createStrategyMap() { + final Map map = new EnumMap<>(State.class); + map.put(State.CLOSED, new StateStrategyClosed()); + map.put(State.OPEN, new StateStrategyOpen()); + return map; + } + + /** + * An internally used data class holding information about the checks performed by + * this class. Basically, the number of received events and the start time of the + * current check interval are stored. + */ + private static class CheckIntervalData { + /** The counter for events. */ + private final int eventCount; + + /** The start time of the current check interval. */ + private final long checkIntervalStart; + + /** + * Creates a new instance of {@code CheckIntervalData}. + * + * @param count the current count value + * @param intervalStart the start time of the check interval + */ + public CheckIntervalData(final int count, final long intervalStart) { + eventCount = count; + checkIntervalStart = intervalStart; + } + + /** + * Returns the event counter. + * + * @return the number of received events + */ + public int getEventCount() { + return eventCount; + } + + /** + * Returns the start time of the current check interval. + * + * @return the check interval start time + */ + public long getCheckIntervalStart() { + return checkIntervalStart; + } + + /** + * Returns a new instance of {@code CheckIntervalData} with the event counter + * incremented by the given delta. If the delta is 0, this object is returned. + * + * @param delta the delta + * @return the updated instance + */ + public CheckIntervalData increment(final int delta) { + return (delta != 0) ? new CheckIntervalData(getEventCount() + delta, + getCheckIntervalStart()) : this; + } + } + + /** + * Internally used class for executing check logic based on the current state of the + * circuit breaker. Having this logic extracted into special classes avoids complex + * if-then-else cascades. + */ + private abstract static class StateStrategy { + /** + * Returns a flag whether the end of the current check interval is reached. + * + * @param breaker the {@code CircuitBreaker} + * @param currentData the current state object + * @param now the current time + * @return a flag whether the end of the current check interval is reached + */ + public boolean isCheckIntervalFinished(final EventCountCircuitBreaker breaker, + final CheckIntervalData currentData, final long now) { + return now - currentData.getCheckIntervalStart() > fetchCheckInterval(breaker); + } + + /** + * Checks whether the specified {@code CheckIntervalData} objects indicate that a + * state transition should occur. Here the logic which checks for thresholds + * depending on the current state is implemented. + * + * @param breaker the {@code CircuitBreaker} + * @param currentData the current {@code CheckIntervalData} object + * @param nextData the updated {@code CheckIntervalData} object + * @return a flag whether a state transition should be performed + */ + public abstract boolean isStateTransition(EventCountCircuitBreaker breaker, + CheckIntervalData currentData, CheckIntervalData nextData); + + /** + * Obtains the check interval to applied for the represented state from the given + * {@code CircuitBreaker}. + * + * @param breaker the {@code CircuitBreaker} + * @return the check interval to be applied + */ + protected abstract long fetchCheckInterval(EventCountCircuitBreaker breaker); + } + + /** + * A specialized {@code StateStrategy} implementation for the state closed. + */ + private static class StateStrategyClosed extends StateStrategy { + + /** + * {@inheritDoc} + */ + @Override + public boolean isStateTransition(final EventCountCircuitBreaker breaker, + final CheckIntervalData currentData, final CheckIntervalData nextData) { + return nextData.getEventCount() > breaker.getOpeningThreshold(); + } + + /** + * {@inheritDoc} + */ + @Override + protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) { + return breaker.getOpeningInterval(); + } + } + + /** + * A specialized {@code StateStrategy} implementation for the state open. + */ + private static class StateStrategyOpen extends StateStrategy { + /** + * {@inheritDoc} + */ + @Override + public boolean isStateTransition(final EventCountCircuitBreaker breaker, + final CheckIntervalData currentData, final CheckIntervalData nextData) { + return nextData.getCheckIntervalStart() != currentData + .getCheckIntervalStart() + && currentData.getEventCount() < breaker.getClosingThreshold(); + } + + /** + * {@inheritDoc} + */ + @Override + protected long fetchCheckInterval(final EventCountCircuitBreaker breaker) { + return breaker.getClosingInterval(); + } + } + +} diff --git a/src/org/apache/commons/lang3/concurrent/LazyInitializer.java b/src/org/apache/commons/lang3/concurrent/LazyInitializer.java new file mode 100644 index 0000000..2b2f72d --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/LazyInitializer.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +/** + *

              + * This class provides a generic implementation of the lazy initialization + * pattern. + *

              + *

              + * Sometimes an application has to deal with an object only under certain + * circumstances, e.g. when the user selects a specific menu item or if a + * special event is received. If the creation of the object is costly or the + * consumption of memory or other system resources is significant, it may make + * sense to defer the creation of this object until it is really needed. This is + * a use case for the lazy initialization pattern. + *

              + *

              + * This abstract base class provides an implementation of the double-check idiom + * for an instance field as discussed in Joshua Bloch's "Effective Java", 2nd + * edition, item 71. The class already implements all necessary synchronization. + * A concrete subclass has to implement the {@code initialize()} method, which + * actually creates the wrapped data object. + *

              + *

              + * As an usage example consider that we have a class {@code ComplexObject} whose + * instantiation is a complex operation. In order to apply lazy initialization + * to this class, a subclass of {@code LazyInitializer} has to be created: + *

              + * + *
              + * public class ComplexObjectInitializer extends LazyInitializer<ComplexObject> {
              + *     @Override
              + *     protected ComplexObject initialize() {
              + *         return new ComplexObject();
              + *     }
              + * }
              + * 
              + * + *

              + * Access to the data object is provided through the {@code get()} method. So, + * code that wants to obtain the {@code ComplexObject} instance would simply + * look like this: + *

              + * + *
              + * // Create an instance of the lazy initializer
              + * ComplexObjectInitializer initializer = new ComplexObjectInitializer();
              + * ...
              + * // When the object is actually needed:
              + * ComplexObject cobj = initializer.get();
              + * 
              + * + *

              + * If multiple threads call the {@code get()} method when the object has not yet + * been created, they are blocked until initialization completes. The algorithm + * guarantees that only a single instance of the wrapped object class is + * created, which is passed to all callers. Once initialized, calls to the + * {@code get()} method are pretty fast because no synchronization is needed + * (only an access to a volatile member field). + *

              + * + * @since 3.0 + * @param the type of the object managed by this initializer class + */ +public abstract class LazyInitializer implements ConcurrentInitializer { + + private static final Object NO_INIT = new Object(); + + @SuppressWarnings("unchecked") + /** Stores the managed object. */ + private volatile T object = (T) NO_INIT; + + /** + * Returns the object wrapped by this instance. On first access the object + * is created. After that it is cached and can be accessed pretty fast. + * + * @return the object initialized by this {@code LazyInitializer} + * @throws ConcurrentException if an error occurred during initialization of + * the object + */ + @Override + public T get() throws ConcurrentException { + // use a temporary variable to reduce the number of reads of the + // volatile field + T result = object; + + if (result == NO_INIT) { + synchronized (this) { + result = object; + if (result == NO_INIT) { + object = result = initialize(); + } + } + } + + return result; + } + + /** + * Creates and initializes the object managed by this {@code + * LazyInitializer}. This method is called by {@link #get()} when the object + * is accessed for the first time. An implementation can focus on the + * creation of the object. No synchronization is needed, as this is already + * handled by {@code get()}. + * + * @return the managed data object + * @throws ConcurrentException if an error occurs during object creation + */ + protected abstract T initialize() throws ConcurrentException; +} diff --git a/src/org/apache/commons/lang3/concurrent/Memoizer.java b/src/org/apache/commons/lang3/concurrent/Memoizer.java new file mode 100644 index 0000000..fb2c154 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/Memoizer.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; + +/** + *

              + * Definition of an interface for a wrapper around a calculation that takes a + * single parameter and returns a result. The results for the calculation will + * be cached for future requests. + *

              + *

              + * This is not a fully functional cache, there is no way of limiting or removing + * results once they have been generated. However, it is possible to get the + * implementation to regenerate the result for a given parameter, if an error + * was thrown during the previous calculation, by setting the option during the + * construction of the class. If this is not set the class will return the + * cached exception. + *

              + *

              + * Thanks should go to Brian Goetz, Tim Peierls and the members of JCP JSR-166 + * Expert Group for coming up with the original implementation of the class. It + * was also published within Java Concurrency in Practice as a sample. + *

              + * + * @param + * the type of the input to the calculation + * @param + * the type of the output of the calculation + * + * @since 3.6 + */ +public class Memoizer implements Computable { + + private final ConcurrentMap> cache = new ConcurrentHashMap<>(); + private final Computable computable; + private final boolean recalculate; + + /** + *

              + * Constructs a Memoizer for the provided Computable calculation. + *

              + *

              + * If a calculation is thrown an exception for any reason, this exception + * will be cached and returned for all future calls with the provided + * parameter. + *

              + * + * @param computable + * the computation whose results should be memorized + */ + public Memoizer(final Computable computable) { + this(computable, false); + } + + /** + *

              + * Constructs a Memoizer for the provided Computable calculation, with the + * option of whether a Computation that experiences an error should + * recalculate on subsequent calls or return the same cached exception. + *

              + * + * @param computable + * the computation whose results should be memorized + * @param recalculate + * determines whether the computation should be recalculated on + * subsequent calls if the previous call failed + */ + public Memoizer(final Computable computable, final boolean recalculate) { + this.computable = computable; + this.recalculate = recalculate; + } + + /** + *

              + * This method will return the result of the calculation and cache it, if it + * has not previously been calculated. + *

              + *

              + * This cache will also cache exceptions that occur during the computation + * if the {@code recalculate} parameter is the constructor was set to + * {@code false}, or not set. Otherwise, if an exception happened on the + * previous calculation, the method will attempt again to generate a value. + *

              + * + * @param arg + * the argument for the calculation + * @return the result of the calculation + * @throws InterruptedException + * thrown if the calculation is interrupted + */ + @Override + public O compute(final I arg) throws InterruptedException { + while (true) { + Future future = cache.get(arg); + if (future == null) { + final Callable eval = new Callable() { + + @Override + public O call() throws InterruptedException { + return computable.compute(arg); + } + }; + final FutureTask futureTask = new FutureTask<>(eval); + future = cache.putIfAbsent(arg, futureTask); + if (future == null) { + future = futureTask; + futureTask.run(); + } + } + try { + return future.get(); + } catch (final CancellationException e) { + cache.remove(arg, future); + } catch (final ExecutionException e) { + if (recalculate) { + cache.remove(arg, future); + } + + throw launderException(e.getCause()); + } + } + } + + /** + *

              + * This method launders a Throwable to either a RuntimeException, Error or + * any other Exception wrapped in an IllegalStateException. + *

              + * + * @param throwable + * the throwable to laundered + * @return a RuntimeException, Error or an IllegalStateException + */ + private RuntimeException launderException(final Throwable throwable) { + if (throwable instanceof RuntimeException) { + return (RuntimeException) throwable; + } else if (throwable instanceof Error) { + throw (Error) throwable; + } else { + throw new IllegalStateException("Unchecked exception", throwable); + } + } +} diff --git a/src/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java b/src/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java new file mode 100644 index 0000000..c672538 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/MultiBackgroundInitializer.java @@ -0,0 +1,351 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +/** + *

              + * A specialized {@link BackgroundInitializer} implementation that can deal with + * multiple background initialization tasks. + *

              + *

              + * This class has a similar purpose as {@link BackgroundInitializer}. However, + * it is not limited to a single background initialization task. Rather it + * manages an arbitrary number of {@code BackgroundInitializer} objects, + * executes them, and waits until they are completely initialized. This is + * useful for applications that have to perform multiple initialization tasks + * that can run in parallel (i.e. that do not depend on each other). This class + * takes care about the management of an {@code ExecutorService} and shares it + * with the {@code BackgroundInitializer} objects it is responsible for; so the + * using application need not bother with these details. + *

              + *

              + * The typical usage scenario for {@code MultiBackgroundInitializer} is as + * follows: + *

              + *
                + *
              • Create a new instance of the class. Optionally pass in a pre-configured + * {@code ExecutorService}. Alternatively {@code MultiBackgroundInitializer} can + * create a temporary {@code ExecutorService} and delete it after initialization + * is complete.
              • + *
              • Create specialized {@link BackgroundInitializer} objects for the + * initialization tasks to be performed and add them to the {@code + * MultiBackgroundInitializer} using the + * {@link #addInitializer(String, BackgroundInitializer)} method.
              • + *
              • After all initializers have been added, call the {@link #start()} method. + *
              • + *
              • When access to the result objects produced by the {@code + * BackgroundInitializer} objects is needed call the {@link #get()} method. The + * object returned here provides access to all result objects created during + * initialization. It also stores information about exceptions that have + * occurred.
              • + *
              + *

              + * {@code MultiBackgroundInitializer} starts a special controller task that + * starts all {@code BackgroundInitializer} objects added to the instance. + * Before the an initializer is started it is checked whether this initializer + * already has an {@code ExecutorService} set. If this is the case, this {@code + * ExecutorService} is used for running the background task. Otherwise the + * current {@code ExecutorService} of this {@code MultiBackgroundInitializer} is + * shared with the initializer. + *

              + *

              + * The easiest way of using this class is to let it deal with the management of + * an {@code ExecutorService} itself: If no external {@code ExecutorService} is + * provided, the class creates a temporary {@code ExecutorService} (that is + * capable of executing all background tasks in parallel) and destroys it at the + * end of background processing. + *

              + *

              + * Alternatively an external {@code ExecutorService} can be provided - either at + * construction time or later by calling the + * {@link #setExternalExecutor(ExecutorService)} method. In this case all + * background tasks are scheduled at this external {@code ExecutorService}. + * Important note: When using an external {@code + * ExecutorService} be sure that the number of threads managed by the service is + * large enough. Otherwise a deadlock can happen! This is the case in the + * following scenario: {@code MultiBackgroundInitializer} starts a task that + * starts all registered {@code BackgroundInitializer} objects and waits for + * their completion. If for instance a single threaded {@code ExecutorService} + * is used, none of the background tasks can be executed, and the task created + * by {@code MultiBackgroundInitializer} waits forever. + *

              + * + * @since 3.0 + */ +public class MultiBackgroundInitializer + extends + BackgroundInitializer { + /** A map with the child initializers. */ + private final Map> childInitializers = + new HashMap<>(); + + /** + * Creates a new instance of {@code MultiBackgroundInitializer}. + */ + public MultiBackgroundInitializer() { + super(); + } + + /** + * Creates a new instance of {@code MultiBackgroundInitializer} and + * initializes it with the given external {@code ExecutorService}. + * + * @param exec the {@code ExecutorService} for executing the background + * tasks + */ + public MultiBackgroundInitializer(final ExecutorService exec) { + super(exec); + } + + /** + * Adds a new {@code BackgroundInitializer} to this object. When this + * {@code MultiBackgroundInitializer} is started, the given initializer will + * be processed. This method must not be called after {@link #start()} has + * been invoked. + * + * @param name the name of the initializer (must not be null) + * @param init the {@code BackgroundInitializer} to add (must not be + * null) + * @throws IllegalArgumentException if a required parameter is missing + * @throws IllegalStateException if {@code start()} has already been called + */ + public void addInitializer(final String name, final BackgroundInitializer init) { + if (name == null) { + throw new IllegalArgumentException( + "Name of child initializer must not be null!"); + } + if (init == null) { + throw new IllegalArgumentException( + "Child initializer must not be null!"); + } + + synchronized (this) { + if (isStarted()) { + throw new IllegalStateException( + "addInitializer() must not be called after start()!"); + } + childInitializers.put(name, init); + } + } + + /** + * Returns the number of tasks needed for executing all child {@code + * BackgroundInitializer} objects in parallel. This implementation sums up + * the required tasks for all child initializers (which is necessary if one + * of the child initializers is itself a {@code MultiBackgroundInitializer} + * ). Then it adds 1 for the control task that waits for the completion of + * the children. + * + * @return the number of tasks required for background processing + */ + @Override + protected int getTaskCount() { + int result = 1; + + for (final BackgroundInitializer bi : childInitializers.values()) { + result += bi.getTaskCount(); + } + + return result; + } + + /** + * Creates the results object. This implementation starts all child {@code + * BackgroundInitializer} objects. Then it collects their results and + * creates a {@code MultiBackgroundInitializerResults} object with this + * data. If a child initializer throws a checked exceptions, it is added to + * the results object. Unchecked exceptions are propagated. + * + * @return the results object + * @throws Exception if an error occurs + */ + @Override + protected MultiBackgroundInitializerResults initialize() throws Exception { + Map> inits; + synchronized (this) { + // create a snapshot to operate on + inits = new HashMap<>( + childInitializers); + } + + // start the child initializers + final ExecutorService exec = getActiveExecutor(); + for (final BackgroundInitializer bi : inits.values()) { + if (bi.getExternalExecutor() == null) { + // share the executor service if necessary + bi.setExternalExecutor(exec); + } + bi.start(); + } + + // collect the results + final Map results = new HashMap<>(); + final Map excepts = new HashMap<>(); + for (final Map.Entry> e : inits.entrySet()) { + try { + results.put(e.getKey(), e.getValue().get()); + } catch (final ConcurrentException cex) { + excepts.put(e.getKey(), cex); + } + } + + return new MultiBackgroundInitializerResults(inits, results, excepts); + } + + /** + * A data class for storing the results of the background initialization + * performed by {@code MultiBackgroundInitializer}. Objects of this inner + * class are returned by {@link MultiBackgroundInitializer#initialize()}. + * They allow access to all result objects produced by the + * {@link BackgroundInitializer} objects managed by the owning instance. It + * is also possible to retrieve status information about single + * {@link BackgroundInitializer}s, i.e. whether they completed normally or + * caused an exception. + */ + public static class MultiBackgroundInitializerResults { + /** A map with the child initializers. */ + private final Map> initializers; + + /** A map with the result objects. */ + private final Map resultObjects; + + /** A map with the exceptions. */ + private final Map exceptions; + + /** + * Creates a new instance of {@code MultiBackgroundInitializerResults} + * and initializes it with maps for the {@code BackgroundInitializer} + * objects, their result objects and the exceptions thrown by them. + * + * @param inits the {@code BackgroundInitializer} objects + * @param results the result objects + * @param excepts the exceptions + */ + private MultiBackgroundInitializerResults( + final Map> inits, + final Map results, + final Map excepts) { + initializers = inits; + resultObjects = results; + exceptions = excepts; + } + + /** + * Returns the {@code BackgroundInitializer} with the given name. If the + * name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the {@code BackgroundInitializer} with this name + * @throws NoSuchElementException if the name cannot be resolved + */ + public BackgroundInitializer getInitializer(final String name) { + return checkName(name); + } + + /** + * Returns the result object produced by the {@code + * BackgroundInitializer} with the given name. This is the object + * returned by the initializer's {@code initialize()} method. If this + * {@code BackgroundInitializer} caused an exception, null is + * returned. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the result object produced by this {@code + * BackgroundInitializer} + * @throws NoSuchElementException if the name cannot be resolved + */ + public Object getResultObject(final String name) { + checkName(name); + return resultObjects.get(name); + } + + /** + * Returns a flag whether the {@code BackgroundInitializer} with the + * given name caused an exception. + * + * @param name the name of the {@code BackgroundInitializer} + * @return a flag whether this initializer caused an exception + * @throws NoSuchElementException if the name cannot be resolved + */ + public boolean isException(final String name) { + checkName(name); + return exceptions.containsKey(name); + } + + /** + * Returns the {@code ConcurrentException} object that was thrown by the + * {@code BackgroundInitializer} with the given name. If this + * initializer did not throw an exception, the return value is + * null. If the name cannot be resolved, an exception is thrown. + * + * @param name the name of the {@code BackgroundInitializer} + * @return the exception thrown by this initializer + * @throws NoSuchElementException if the name cannot be resolved + */ + public ConcurrentException getException(final String name) { + checkName(name); + return exceptions.get(name); + } + + /** + * Returns a set with the names of all {@code BackgroundInitializer} + * objects managed by the {@code MultiBackgroundInitializer}. + * + * @return an (unmodifiable) set with the names of the managed {@code + * BackgroundInitializer} objects + */ + public Set initializerNames() { + return Collections.unmodifiableSet(initializers.keySet()); + } + + /** + * Returns a flag whether the whole initialization was successful. This + * is the case if no child initializer has thrown an exception. + * + * @return a flag whether the initialization was successful + */ + public boolean isSuccessful() { + return exceptions.isEmpty(); + } + + /** + * Checks whether an initializer with the given name exists. If not, + * throws an exception. If it exists, the associated child initializer + * is returned. + * + * @param name the name to check + * @return the initializer with this name + * @throws NoSuchElementException if the name is unknown + */ + private BackgroundInitializer checkName(final String name) { + final BackgroundInitializer init = initializers.get(name); + if (init == null) { + throw new NoSuchElementException( + "No child initializer with name " + name); + } + + return init; + } + } +} diff --git a/src/org/apache/commons/lang3/concurrent/ThresholdCircuitBreaker.java b/src/org/apache/commons/lang3/concurrent/ThresholdCircuitBreaker.java new file mode 100644 index 0000000..2238d74 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/ThresholdCircuitBreaker.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.atomic.AtomicLong; + +/** + *

              + * A simple implementation of the Circuit Breaker pattern + * that opens if the requested increment amount is greater than a given threshold. + *

              + * + *

              + * It contains an internal counter that starts in zero, and each call increments the counter by a given amount. + * If the threshold is zero, the circuit breaker will be in a permanent open state. + *

              + * + *

              + * An example of use case could be a memory circuit breaker. + *

              + * + *
              + * long threshold = 10L;
              + * ThresholdCircuitBreaker breaker = new ThresholdCircuitBreaker(10L);
              + * ...
              + * public void handleRequest(Request request) {
              + *     long memoryUsed = estimateMemoryUsage(request);
              + *     if (breaker.incrementAndCheckState(memoryUsed)) {
              + *         // actually handle this request
              + *     } else {
              + *         // do something else, e.g. send an error code
              + *     }
              + * }
              + * 
              + * + *

              #Thread safe#

              + * @since 3.5 + */ +public class ThresholdCircuitBreaker extends AbstractCircuitBreaker { + /** + * The initial value of the internal counter. + */ + private final static long INITIAL_COUNT = 0L; + + /** + * The threshold. + */ + private final long threshold; + + /** + * Controls the amount used. + */ + private final AtomicLong used; + + /** + *

              Creates a new instance of {@code ThresholdCircuitBreaker} and initializes the threshold.

              + * + * @param threshold the threshold. + */ + public ThresholdCircuitBreaker(final long threshold) { + super(); + this.used = new AtomicLong(INITIAL_COUNT); + this.threshold = threshold; + } + + /** + * Gets the threshold. + * + * @return the threshold + */ + public long getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean checkState() throws CircuitBreakingException { + return isOpen(); + } + + /** + * {@inheritDoc} + * + *

              Resets the internal counter back to its initial value (zero).

              + */ + @Override + public void close() { + super.close(); + this.used.set(INITIAL_COUNT); + } + + /** + * {@inheritDoc} + * + *

              If the threshold is zero, the circuit breaker will be in a permanent open state.

              + */ + @Override + public boolean incrementAndCheckState(final Long increment) throws CircuitBreakingException { + if (threshold == 0) { + open(); + } + + final long used = this.used.addAndGet(increment); + if (used > threshold) { + open(); + } + + return checkState(); + } + +} diff --git a/src/org/apache/commons/lang3/concurrent/TimedSemaphore.java b/src/org/apache/commons/lang3/concurrent/TimedSemaphore.java new file mode 100644 index 0000000..0b7dc39 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/TimedSemaphore.java @@ -0,0 +1,470 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

              + * A specialized semaphore implementation that provides a number of + * permits in a given time frame. + *

              + *

              + * This class is similar to the {@code java.util.concurrent.Semaphore} class + * provided by the JDK in that it manages a configurable number of permits. + * Using the {@link #acquire()} method a permit can be requested by a thread. + * However, there is an additional timing dimension: there is no {@code + * release()} method for freeing a permit, but all permits are automatically + * released at the end of a configurable time frame. If a thread calls + * {@link #acquire()} and the available permits are already exhausted for this + * time frame, the thread is blocked. When the time frame ends all permits + * requested so far are restored, and blocking threads are waked up again, so + * that they can try to acquire a new permit. This basically means that in the + * specified time frame only the given number of operations is possible. + *

              + *

              + * A use case for this class is to artificially limit the load produced by a + * process. As an example consider an application that issues database queries + * on a production system in a background process to gather statistical + * information. This background processing should not produce so much database + * load that the functionality and the performance of the production system are + * impacted. Here a {@code TimedSemaphore} could be installed to guarantee that + * only a given number of database queries are issued per second. + *

              + *

              + * A thread class for performing database queries could look as follows: + *

              + * + *
              + * public class StatisticsThread extends Thread {
              + *     // The semaphore for limiting database load.
              + *     private final TimedSemaphore semaphore;
              + *     // Create an instance and set the semaphore
              + *     public StatisticsThread(TimedSemaphore timedSemaphore) {
              + *         semaphore = timedSemaphore;
              + *     }
              + *     // Gather statistics
              + *     public void run() {
              + *         try {
              + *             while(true) {
              + *                 semaphore.acquire();   // limit database load
              + *                 performQuery();        // issue a query
              + *             }
              + *         } catch(InterruptedException) {
              + *             // fall through
              + *         }
              + *     }
              + *     ...
              + * }
              + * 
              + * + *

              + * The following code fragment shows how a {@code TimedSemaphore} is created + * that allows only 10 operations per second and passed to the statistics + * thread: + *

              + * + *
              + * TimedSemaphore sem = new TimedSemaphore(1, TimeUnit.SECOND, 10);
              + * StatisticsThread thread = new StatisticsThread(sem);
              + * thread.start();
              + * 
              + * + *

              + * When creating an instance the time period for the semaphore must be + * specified. {@code TimedSemaphore} uses an executor service with a + * corresponding period to monitor this interval. The {@code + * ScheduledExecutorService} to be used for this purpose can be provided at + * construction time. Alternatively the class creates an internal executor + * service. + *

              + *

              + * Client code that uses {@code TimedSemaphore} has to call the + * {@link #acquire()} method in each processing step. {@code TimedSemaphore} + * keeps track of the number of invocations of the {@link #acquire()} method and + * blocks the calling thread if the counter exceeds the limit specified. When + * the timer signals the end of the time period the counter is reset and all + * waiting threads are released. Then another cycle can start. + *

              + *

              + * An alternative to {@code acquire()} is the {@link #tryAcquire()} method. This + * method checks whether the semaphore is under the specified limit and + * increases the internal counter if this is the case. The return value is then + * true, and the calling thread can continue with its action. + * If the semaphore is already at its limit, {@code tryAcquire()} immediately + * returns false without blocking; the calling thread must + * then abort its action. This usage scenario prevents blocking of threads. + *

              + *

              + * It is possible to modify the limit at any time using the + * {@link #setLimit(int)} method. This is useful if the load produced by an + * operation has to be adapted dynamically. In the example scenario with the + * thread collecting statistics it may make sense to specify a low limit during + * day time while allowing a higher load in the night time. Reducing the limit + * takes effect immediately by blocking incoming callers. If the limit is + * increased, waiting threads are not released immediately, but wake up when the + * timer runs out. Then, in the next period more processing steps can be + * performed without blocking. By setting the limit to 0 the semaphore can be + * switched off: in this mode the {@link #acquire()} method never blocks, but + * lets all callers pass directly. + *

              + *

              + * When the {@code TimedSemaphore} is no more needed its {@link #shutdown()} + * method should be called. This causes the periodic task that monitors the time + * interval to be canceled. If the {@code ScheduledExecutorService} has been + * created by the semaphore at construction time, it is also shut down. + * resources. After that {@link #acquire()} must not be called any more. + *

              + * + * @since 3.0 + */ +public class TimedSemaphore { + /** + * Constant for a value representing no limit. If the limit is set to a + * value less or equal this constant, the {@code TimedSemaphore} will be + * effectively switched off. + */ + public static final int NO_LIMIT = 0; + + /** Constant for the thread pool size for the executor. */ + private static final int THREAD_POOL_SIZE = 1; + + /** The executor service for managing the timer thread. */ + private final ScheduledExecutorService executorService; + + /** Stores the period for this timed semaphore. */ + private final long period; + + /** The time unit for the period. */ + private final TimeUnit unit; + + /** A flag whether the executor service was created by this object. */ + private final boolean ownExecutor; + + /** A future object representing the timer task. */ + private ScheduledFuture task; // @GuardedBy("this") + + /** Stores the total number of invocations of the acquire() method. */ + private long totalAcquireCount; // @GuardedBy("this") + + /** + * The counter for the periods. This counter is increased every time a + * period ends. + */ + private long periodCount; // @GuardedBy("this") + + /** The limit. */ + private int limit; // @GuardedBy("this") + + /** The current counter. */ + private int acquireCount; // @GuardedBy("this") + + /** The number of invocations of acquire() in the last period. */ + private int lastCallsPerPeriod; // @GuardedBy("this") + + /** A flag whether shutdown() was called. */ + private boolean shutdown; // @GuardedBy("this") + + /** + * Creates a new instance of {@link TimedSemaphore} and initializes it with + * the given time period and the limit. + * + * @param timePeriod the time period + * @param timeUnit the unit for the period + * @param limit the limit for the semaphore + * @throws IllegalArgumentException if the period is less or equals 0 + */ + public TimedSemaphore(final long timePeriod, final TimeUnit timeUnit, final int limit) { + this(null, timePeriod, timeUnit, limit); + } + + /** + * Creates a new instance of {@link TimedSemaphore} and initializes it with + * an executor service, the given time period, and the limit. The executor + * service will be used for creating a periodic task for monitoring the time + * period. It can be null, then a default service will be created. + * + * @param service the executor service + * @param timePeriod the time period + * @param timeUnit the unit for the period + * @param limit the limit for the semaphore + * @throws IllegalArgumentException if the period is less or equals 0 + */ + public TimedSemaphore(final ScheduledExecutorService service, final long timePeriod, + final TimeUnit timeUnit, final int limit) { + Validate.inclusiveBetween(1, Long.MAX_VALUE, timePeriod, "Time period must be greater than 0!"); + + period = timePeriod; + unit = timeUnit; + + if (service != null) { + executorService = service; + ownExecutor = false; + } else { + final ScheduledThreadPoolExecutor s = new ScheduledThreadPoolExecutor( + THREAD_POOL_SIZE); + s.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); + s.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + executorService = s; + ownExecutor = true; + } + + setLimit(limit); + } + + /** + * Returns the limit enforced by this semaphore. The limit determines how + * many invocations of {@link #acquire()} are allowed within the monitored + * period. + * + * @return the limit + */ + public final synchronized int getLimit() { + return limit; + } + + /** + * Sets the limit. This is the number of times the {@link #acquire()} method + * can be called within the time period specified. If this limit is reached, + * further invocations of {@link #acquire()} will block. Setting the limit + * to a value <= {@link #NO_LIMIT} will cause the limit to be disabled, + * i.e. an arbitrary number of{@link #acquire()} invocations is allowed in + * the time period. + * + * @param limit the limit + */ + public final synchronized void setLimit(final int limit) { + this.limit = limit; + } + + /** + * Initializes a shutdown. After that the object cannot be used any more. + * This method can be invoked an arbitrary number of times. All invocations + * after the first one do not have any effect. + */ + public synchronized void shutdown() { + if (!shutdown) { + + if (ownExecutor) { + // if the executor was created by this instance, it has + // to be shutdown + getExecutorService().shutdownNow(); + } + if (task != null) { + task.cancel(false); + } + + shutdown = true; + } + } + + /** + * Tests whether the {@link #shutdown()} method has been called on this + * object. If this method returns true, this instance cannot be used + * any longer. + * + * @return a flag whether a shutdown has been performed + */ + public synchronized boolean isShutdown() { + return shutdown; + } + + /** + * Acquires a permit from this semaphore. This method will block if + * the limit for the current period has already been reached. If + * {@link #shutdown()} has already been invoked, calling this method will + * cause an exception. The very first call of this method starts the timer + * task which monitors the time period set for this {@code TimedSemaphore}. + * From now on the semaphore is active. + * + * @throws InterruptedException if the thread gets interrupted + * @throws IllegalStateException if this semaphore is already shut down + */ + public synchronized void acquire() throws InterruptedException { + prepareAcquire(); + + boolean canPass; + do { + canPass = acquirePermit(); + if (!canPass) { + wait(); + } + } while (!canPass); + } + + /** + * Tries to acquire a permit from this semaphore. If the limit of this semaphore has + * not yet been reached, a permit is acquired, and this method returns + * true. Otherwise, this method returns immediately with the result + * false. + * + * @return true if a permit could be acquired; false + * otherwise + * @throws IllegalStateException if this semaphore is already shut down + * @since 3.5 + */ + public synchronized boolean tryAcquire() { + prepareAcquire(); + return acquirePermit(); + } + + /** + * Returns the number of (successful) acquire invocations during the last + * period. This is the number of times the {@link #acquire()} method was + * called without blocking. This can be useful for testing or debugging + * purposes or to determine a meaningful threshold value. If a limit is set, + * the value returned by this method won't be greater than this limit. + * + * @return the number of non-blocking invocations of the {@link #acquire()} + * method + */ + public synchronized int getLastAcquiresPerPeriod() { + return lastCallsPerPeriod; + } + + /** + * Returns the number of invocations of the {@link #acquire()} method for + * the current period. This may be useful for testing or debugging purposes. + * + * @return the current number of {@link #acquire()} invocations + */ + public synchronized int getAcquireCount() { + return acquireCount; + } + + /** + * Returns the number of calls to the {@link #acquire()} method that can + * still be performed in the current period without blocking. This method + * can give an indication whether it is safe to call the {@link #acquire()} + * method without risking to be suspended. However, there is no guarantee + * that a subsequent call to {@link #acquire()} actually is not-blocking + * because in the mean time other threads may have invoked the semaphore. + * + * @return the current number of available {@link #acquire()} calls in the + * current period + */ + public synchronized int getAvailablePermits() { + return getLimit() - getAcquireCount(); + } + + /** + * Returns the average number of successful (i.e. non-blocking) + * {@link #acquire()} invocations for the entire life-time of this {@code + * TimedSemaphore}. This method can be used for instance for statistical + * calculations. + * + * @return the average number of {@link #acquire()} invocations per time + * unit + */ + public synchronized double getAverageCallsPerPeriod() { + return periodCount == 0 ? 0 : (double) totalAcquireCount + / (double) periodCount; + } + + /** + * Returns the time period. This is the time monitored by this semaphore. + * Only a given number of invocations of the {@link #acquire()} method is + * possible in this period. + * + * @return the time period + */ + public long getPeriod() { + return period; + } + + /** + * Returns the time unit. This is the unit used by {@link #getPeriod()}. + * + * @return the time unit + */ + public TimeUnit getUnit() { + return unit; + } + + /** + * Returns the executor service used by this instance. + * + * @return the executor service + */ + protected ScheduledExecutorService getExecutorService() { + return executorService; + } + + /** + * Starts the timer. This method is called when {@link #acquire()} is called + * for the first time. It schedules a task to be executed at fixed rate to + * monitor the time period specified. + * + * @return a future object representing the task scheduled + */ + protected ScheduledFuture startTimer() { + return getExecutorService().scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + endOfPeriod(); + } + }, getPeriod(), getPeriod(), getUnit()); + } + + /** + * The current time period is finished. This method is called by the timer + * used internally to monitor the time period. It resets the counter and + * releases the threads waiting for this barrier. + */ + synchronized void endOfPeriod() { + lastCallsPerPeriod = acquireCount; + totalAcquireCount += acquireCount; + periodCount++; + acquireCount = 0; + notifyAll(); + } + + /** + * Prepares an acquire operation. Checks for the current state and starts the internal + * timer if necessary. This method must be called with the lock of this object held. + */ + private void prepareAcquire() { + if (isShutdown()) { + throw new IllegalStateException("TimedSemaphore is shut down!"); + } + + if (task == null) { + task = startTimer(); + } + } + + /** + * Internal helper method for acquiring a permit. This method checks whether currently + * a permit can be acquired and - if so - increases the internal counter. The return + * value indicates whether a permit could be acquired. This method must be called with + * the lock of this object held. + * + * @return a flag whether a permit could be acquired + */ + private boolean acquirePermit() { + if (getLimit() <= NO_LIMIT || acquireCount < getLimit()) { + acquireCount++; + return true; + } + return false; + } +} diff --git a/src/org/apache/commons/lang3/concurrent/annotation/GuardedBy.java b/src/org/apache/commons/lang3/concurrent/annotation/GuardedBy.java new file mode 100644 index 0000000..abd2416 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/annotation/GuardedBy.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Describes the lock which guards a field or method. + */ +@Documented +@Target({ ElementType.FIELD, ElementType.METHOD }) +@Retention(RetentionPolicy.CLASS) +public @interface GuardedBy { + + /** + * Gets the lock which guards a field or method. + * + * @return the lock which guards a field or method. + */ + String value(); +} diff --git a/src/org/apache/commons/lang3/concurrent/annotation/Immutable.java b/src/org/apache/commons/lang3/concurrent/annotation/Immutable.java new file mode 100644 index 0000000..0de343c --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/annotation/Immutable.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Describes a type as immutable. + */ +@Documented +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface Immutable { + // marker annotation, empty body +} diff --git a/src/org/apache/commons/lang3/concurrent/annotation/NotThreadSafe.java b/src/org/apache/commons/lang3/concurrent/annotation/NotThreadSafe.java new file mode 100644 index 0000000..78b2b03 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/annotation/NotThreadSafe.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Describes this type as not thread-safe. + * + * @see ThreadSafe + */ +@Documented +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface NotThreadSafe { + // marker annotation, empty body +} diff --git a/src/org/apache/commons/lang3/concurrent/annotation/ThreadSafe.java b/src/org/apache/commons/lang3/concurrent/annotation/ThreadSafe.java new file mode 100644 index 0000000..cef8c64 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/annotation/ThreadSafe.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.concurrent.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Describes this type as thread-safe. + * + * @see NotThreadSafe + */ +@Documented +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface ThreadSafe { + // marker annotation, empty body +} diff --git a/src/org/apache/commons/lang3/concurrent/annotation/package-info.java b/src/org/apache/commons/lang3/concurrent/annotation/package-info.java new file mode 100644 index 0000000..3f29ebf --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/annotation/package-info.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Provides annotations to document classes' thread safety

              + * + * @since 3.6 + */ +package org.apache.commons.lang3.concurrent.annotation; diff --git a/src/org/apache/commons/lang3/concurrent/package-info.java b/src/org/apache/commons/lang3/concurrent/package-info.java new file mode 100644 index 0000000..7f2a6b8 --- /dev/null +++ b/src/org/apache/commons/lang3/concurrent/package-info.java @@ -0,0 +1,438 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Provides support classes for multi-threaded programming. + * This package is intended to be an extension to {@link java.util.concurrent}. + * These classes are thread-safe.

              + * + *

              + * + *

              A group of classes deals with the correct creation and initialization of objects that are accessed by multiple threads. + * All these classes implement the {@link org.apache.commons.lang3.concurrent.ConcurrentInitializer} interface which provides just a + * single method: + *

              + * + *
              + * 
              + * public interface ConcurrentInitializer<T> {
              + *    T get() throws ConcurrentException;
              + * }
              + * 
              + * 
              + * + *

              A ConcurrentInitializer produces an object. + * By calling the {@link org.apache.commons.lang3.concurrent.ConcurrentInitializer#get() get()} method the object managed by the initializer can be obtained. + * There are different implementations of the interface available + * addressing various use cases: + *

              + * + *

              {@link org.apache.commons.lang3.concurrent.ConstantInitializer} is a very straightforward implementation of the ConcurrentInitializer interface: + * An instance is passed an object when it is constructed. + * In its get() method it simply returns this object. + * This is useful, for instance in unit tests or in cases when you want to pass a specific object to a component which expects a ConcurrentInitializer. + *

              + * + *

              The {@link org.apache.commons.lang3.concurrent.LazyInitializer} class can be used to defer the creation of an object until it is actually used. + * This makes sense, for instance, if the creation of the object is expensive and would slow down application startup or if the object is needed only for special executions. + * LazyInitializer implements the double-check idiom for an instance field as discussed in Joshua Bloch's "Effective Java", 2nd edition, item 71. + * It uses volatile fields to reduce the amount of synchronization. + * Note that this idiom is appropriate for instance fields only. + * For static fields there are superior alternatives.

              + * + *

              We provide an example use case to demonstrate the usage of this class: + * A server application uses multiple worker threads to process client requests. + * If such a request causes a fatal error, an administrator is to be notified using a special messaging service. + * We assume that the creation of the messaging service is an expensive operation. + * So it should only be performed if an error actually occurs. + * Here is where LazyInitializer comes into play. + * We create a specialized subclass for creating and initializing an instance of our messaging service. + * LazyInitializer declares an abstract {@link org.apache.commons.lang3.concurrent.LazyInitializer#initialize() initialize()} method which we have to implement to create the messaging service object:

              + * + *
              + * 
              + * public class MessagingServiceInitializer extends LazyInitializer<MessagingService> {
              + *   protected MessagingService initialize() throws ConcurrentException {
              + *     // Do all necessary steps to create and initialize the service object
              + *     MessagingService service = ...
              + *     return service;
              + *   }
              + * }
              + * 
              + * 
              + * + *

              Now each server thread is passed a reference to a shared instance of our new MessagingServiceInitializer class. + * The threads run in a loop processing client requests. If an error is detected, the messaging service is obtained from the initializer, and the administrator is notified:

              + * + *
              + * 
              + * public class ServerThread implements Runnable {
              + *  // The initializer for obtaining the messaging service.
              + *  private final ConcurrentInitializer<MessagingService> initializer;
              + *
              + *  public ServerThread(ConcurrentInitializer<MessagingService> init) {
              + *    initializer = init;
              + *  }
              + *
              + *  public void run() {
              + *    while (true) {
              + *      try {
              + *        // wait for request
              + *        // process request
              + *      } catch (FatalServerException ex) {
              + *        // get messaging service
              + *        try {
              + *          MessagingService svc = initializer.get();
              + *          svc.notifyAdministrator(ex);
              + *        } catch (ConcurrentException cex) {
              + *          cex.printStackTrace();
              + *        }
              + *      }
              + *    }
              + *  }
              + * }
              + * 
              + * 
              + * + *

              The {@link org.apache.commons.lang3.concurrent.AtomicInitializer} class is very similar to LazyInitializer. + * It serves the same purpose: to defer the creation of an object until it is needed. + * The internal structure is also very similar. + * Again there is an abstract {@link org.apache.commons.lang3.concurrent.AtomicInitializer#initialize() initialize()} method which has to be implemented by concrete subclasses in order to create and initialize the managed object. + * Actually, in our example above we can turn the MessagingServiceInitializer into an atomic initializer by simply changing the extends declaration to refer to AtomicInitializer<MessagingService> as super class.

              + * + *

              With {@link org.apache.commons.lang3.concurrent.AtomicSafeInitializer} there is yet another variant implementing the lazy initializing pattern. + * Its implementation is close to AtomicInitializer; it also uses atomic variables internally and therefore does not need synchronization. + * The name "Safe" is derived from the fact that it implements an additional check which guarantees that the {@link org.apache.commons.lang3.concurrent.AtomicSafeInitializer#initialize() initialize()} method is called only once. + * So it behaves exactly in the same way as LazyInitializer.

              + * + *

              Now, which one of the lazy initializer implementations should you use? + * First of all we have to state that is is problematic to give general recommendations regarding the performance of these classes. + * The initializers make use of low-level functionality whose efficiency depends on multiple factors including the target platform and the number of concurrent threads. + * So developers should make their own benchmarks in scenarios close to their specific use cases. + * The following statements are rules of thumb which have to be verified in practice.

              + * + *

              AtomicInitializer is probably the most efficient implementation due to its lack of synchronization and further checks. + * Its main drawback is that the initialize() method can be called multiple times. + * In cases where this is not an issue AtomicInitializer is a good choice. + * AtomicSafeInitializer and LazyInitializer both guarantee that the initialization method is called only once. + * Because AtomicSafeInitializer does not use synchronization it is probably slightly more efficient than LazyInitializer, but the concrete numbers might depend on the level of concurrency.

              + * + *

              Another implementation of the ConcurrentInitializer interface is {@link org.apache.commons.lang3.concurrent.BackgroundInitializer}. + * It is again an abstract base class with an {@link org.apache.commons.lang3.concurrent.BackgroundInitializer#initialize() initialize()} method that has to be defined by concrete subclasses. + * The idea of BackgroundInitializer is that it calls the initialize() method in a separate worker thread. + * An application creates a background initializer and starts it. + * Then it can continue with its work while the initializer runs in parallel. + * When the application needs the results of the initializer it calls its get() method. + * get() blocks until the initialization is complete. + * This is useful for instance at application startup. + * Here initialization steps (e.g. reading configuration files, opening a database connection, etc.) can be run in background threads while the application shows a splash screen and constructs its UI.

              + * + *

              As a concrete example consider an application that has to read the content of a URL - maybe a page with news - which is to be displayed to the user after login. + * Because loading the data over the network can take some time a specialized implementation of BackgroundInitializer can be created for this purpose:

              + * + *
              + * 
              + * public class URLLoader extends BackgroundInitializer<String> {
              + *   // The URL to be loaded.
              + *   private final URL url;
              + *
              + *   public URLLoader(URL u) {
              + *     url = u;
              + *   }
              + *
              + *   protected String initialize() throws ConcurrentException {
              + *     try {
              + *       InputStream in = url.openStream();
              + *       // read content into string
              + *       ...
              + *       return content;
              + *     } catch (IOException ioex) {
              + *       throw new ConcurrentException(ioex);
              + *     }
              + *   }
              + * }
              + * 
              + * 
              + * + *

              An application creates an instance of URLLoader and starts it. + * Then it can do other things. + * When it needs the content of the URL it calls the initializer's get() method:

              + * + *
              + * 
              + * URL url = new URL("http://www.application-home-page.com/");
              + * URLLoader loader = new URLLoader(url);
              + * loader.start();  // this starts the background initialization
              + *
              + * // do other stuff
              + * ...
              + * // now obtain the content of the URL
              + * String content;
              + * try {
              + *   content = loader.get();  // this may block
              + * } catch (ConcurrentException cex) {
              + *   content = "Error when loading URL " + url;
              + * }
              + * // display content
              + * 
              + * 
              + * + *

              Related to BackgroundInitializer is the {@link org.apache.commons.lang3.concurrent.MultiBackgroundInitializer} class. + * As the name implies, this class can handle multiple initializations in parallel. + * The basic usage scenario is that a MultiBackgroundInitializer instance is created. + * Then an arbitrary number of BackgroundInitializer objects is added using the {@link org.apache.commons.lang3.concurrent.MultiBackgroundInitializer#addInitializer(String, BackgroundInitializer)} method. + * When adding an initializer a string has to be provided which is later used to obtain the result for this initializer. + * When all initializers have been added the {@link org.apache.commons.lang3.concurrent.MultiBackgroundInitializer#start()} method is called. + * This starts processing of all initializers. + * Later the get() method can be called. + * It waits until all initializers have finished their initialization. + * get() returns an object of type {@link org.apache.commons.lang3.concurrent.MultiBackgroundInitializer.MultiBackgroundInitializerResults}. + * This object provides information about all initializations that have been performed. + * It can be checked whether a specific initializer was successful or threw an exception. + * Of course, all initialization results can be queried.

              + * + *

              With MultiBackgroundInitializer we can extend our example to perform multiple initialization steps. + * Suppose that in addition to loading a web site we also want to create a JPA entity manager factory and read a configuration file. + * We assume that corresponding BackgroundInitializer implementations exist. + * The following example fragment shows the usage of MultiBackgroundInitializer for this purpose:

              + * + *
              + * 
              + * MultiBackgroundInitializer initializer = new MultiBackgroundInitializer();
              + * initializer.addInitializer("url", new URLLoader(url));
              + * initializer.addInitializer("jpa", new JPAEMFInitializer());
              + * initializer.addInitializer("config", new ConfigurationInitializer());
              + * initializer.start();  // start background processing
              + *
              + * // do other interesting things in parallel
              + * ...
              + * // evaluate the results of background initialization
              + * MultiBackgroundInitializer.MultiBackgroundInitializerResults results =
              + * initializer.get();
              + * String urlContent = (String) results.getResultObject("url");
              + * EntityManagerFactory emf =
              + * (EntityManagerFactory) results.getResultObject("jpa");
              + * ...
              + * 
              + * 
              + * + *

              The child initializers are added to the multi initializer and are assigned a unique name. + * The object returned by the get() method is then queried for the single results using these unique names.

              + * + *

              If background initializers - including MultiBackgroundInitializer - are created using the standard constructor, they create their own {@link java.util.concurrent.ExecutorService} which is used behind the scenes to execute the worker tasks. + * It is also possible to pass in an ExecutorService when the initializer is constructed. + * That way client code can configure the ExecutorService according to its specific needs; for instance, the number of threads available could be limited.

              + * + *

              Utility Classes

              + * + *

              Another group of classes in the new concurrent package offers some generic functionality related to concurrency. + * There is the {@link org.apache.commons.lang3.concurrent.ConcurrentUtils} class with a bunch of static utility methods. + * One focus of this class is dealing with exceptions thrown by JDK classes. + * Many JDK classes of the executor framework throw exceptions of type {@link java.util.concurrent.ExecutionException} if something goes wrong. + * The root cause of these exceptions can also be a runtime exception or even an error. + * In typical Java programming you often do not want to deal with runtime exceptions directly; rather you let them fall through the hierarchy of method invocations until they reach a central exception handler. + * Checked exceptions in contrast are usually handled close to their occurrence. + * With ExecutionException this principle is violated. + * Because it is a checked exception, an application is forced to handle it even if the cause is a runtime exception. + * So you typically have to inspect the cause of the ExecutionException and test whether it is a checked exception which has to be handled. If this is not the case, the causing exception can be rethrown. + *

              + * + *

              The {@link org.apache.commons.lang3.concurrent.ConcurrentUtils#extractCause(java.util.concurrent.ExecutionException)} method does this work for you. + * It is passed an ExecutionException and tests its root cause. + * If this is an error or a runtime exception, it is directly rethrown. + * Otherwise, an instance of {@link org.apache.commons.lang3.concurrent.ConcurrentException} is created and initialized with the root cause + * (ConcurrentException is a new exception class in the o.a.c.l.concurrent package). + * So if you get such a ConcurrentException, you can be sure that the original cause for the ExecutionException was a checked exception. + * For users who prefer runtime exceptions in general there is also an {@link org.apache.commons.lang3.concurrent.ConcurrentUtils#extractCauseUnchecked(java.util.concurrent.ExecutionException)} method which behaves like extractCause(), but returns the unchecked exception {@link org.apache.commons.lang3.concurrent.ConcurrentRuntimeException} instead.

              + * + *

              In addition to the extractCause() methods there are corresponding {@link org.apache.commons.lang3.concurrent.ConcurrentUtils#handleCause(java.util.concurrent.ExecutionException)} and {@link org.apache.commons.lang3.concurrent.ConcurrentUtils#handleCauseUnchecked(java.util.concurrent.ExecutionException)} methods. + * These methods extract the cause of the passed in ExecutionException and throw the resulting ConcurrentException or ConcurrentRuntimeException. + * This makes it easy to transform an ExecutionException into a ConcurrentException ignoring unchecked exceptions:

              + * + *
              + * 
              + * Future<Object> future = ...;
              + * try {
              + *   Object result = future.get();
              + *   ...
              + * } catch (ExecutionException eex) {
              + *   ConcurrentUtils.handleCause(eex);
              + * }
              + * 
              + * 
              + * + *

              There is also some support for the concurrent initializers introduced in the last sub section. + * The initialize() method is passed a ConcurrentInitializer object and returns the object created by this initializer. + * It is null-safe. + * The initializeUnchecked() method works analogously, but a ConcurrentException throws by the initializer is rethrown as a ConcurrentRuntimeException. + * This is especially useful if the specific ConcurrentInitializer does not throw checked exceptions. + * Using this method the code for requesting the object of an initializer becomes less verbose. + * The direct invocation looks as follows:

              + * + *
              + * 
              + * ConcurrentInitializer<MyClass> initializer = ...;
              + * try {
              + *   MyClass obj = initializer.get();
              + *   // do something with obj
              + * } catch (ConcurrentException cex) {
              + *   // exception handling
              + * }
              + * 
              + * 
              + * + *

              Using the {@link org.apache.commons.lang3.concurrent.ConcurrentUtils#initializeUnchecked(ConcurrentInitializer)} method, this becomes:

              + * + *
              + * 
              + * ConcurrentInitializer<MyClass> initializer = ...;
              + * MyClass obj = ConcurrentUtils.initializeUnchecked(initializer);
              + * // do something with obj
              + * 
              + * 
              + * + *

              Another utility class deals with the creation of threads. + * When using the Executor framework new in JDK 1.5 the developer usually does not have to care about creating threads; the executors create the threads they need on demand. + * However, sometimes it is desired to set some properties of the newly created worker threads. + * This is possible through the {@link java.util.concurrent.ThreadFactory} interface; an implementation of this interface has to be created and passed to an executor on creation time. + * Currently, the JDK does not provide an implementation of ThreadFactory, so one has to start from scratch.

              + * + *

              With {@link org.apache.commons.lang3.concurrent.BasicThreadFactory} Commons Lang has an implementation of ThreadFactory that works out of the box for many common use cases. + * For instance, it is possible to set a naming pattern for the new threads, set the daemon flag and a priority, or install a handler for uncaught exceptions. + * Instances of BasicThreadFactory are created and configured using the nested {@link org.apache.commons.lang3.concurrent.BasicThreadFactory.Builder} class. + * The following example shows a typical usage scenario:

              + * + *
              + * 
              + * BasicThreadFactory factory = new BasicThreadFactory.Builder()
              + *   .namingPattern("worker-thread-%d")
              + *   .daemon(true)
              + *   .uncaughtExceptionHandler(myHandler)
              + *   .build();
              + * ExecutorService exec = Executors.newSingleThreadExecutor(factory);
              + * 
              + * 
              + * + *

              The nested Builder class defines some methods for configuring the new BasicThreadFactory instance. + * Objects of this class are immutable, so these attributes cannot be changed later. + * The naming pattern is a string which can be passed to String.format(). + * The placeholder %d is replaced by an increasing counter value. + * An instance can wrap another ThreadFactory implementation; this is achieved by calling the builder's {@link org.apache.commons.lang3.concurrent.BasicThreadFactory.Builder#wrappedFactory(java.util.concurrent.ThreadFactory) wrappedFactory(ThreadFactory)} method. + * This factory is then used for creating new threads; after that the specific attributes are applied to the new thread. + * If no wrapped factory is set, the default factory provided by the JDK is used.

              + * + *

              Synchronization objects

              + * + *

              The concurrent package also provides some support for specific synchronization problems with threads.

              + * + *

              {@link org.apache.commons.lang3.concurrent.TimedSemaphore} allows restricted access to a resource in a given time frame. + * Similar to a semaphore, a number of permits can be acquired. + * What is new is the fact that the permits available are related to a given time unit. + * For instance, the timed semaphore can be configured to allow 10 permits in a second. + * Now multiple threads access the semaphore and call its {@link org.apache.commons.lang3.concurrent.TimedSemaphore#acquire()} method. + * The semaphore keeps track about the number of granted permits in the current time frame. + * Only 10 calls are allowed; if there are further callers, they are blocked until the time frame (one second in this example) is over. + * Then all blocking threads are released, and the counter of available permits is reset to 0. + * So the game can start anew.

              + * + *

              What are use cases for TimedSemaphore? + * One example is to artificially limit the load produced by multiple threads. + * Consider a batch application accessing a database to extract statistical data. + * The application runs multiple threads which issue database queries in parallel and perform some calculation on the results. + * If the database to be processed is huge and is also used by a production system, multiple factors have to be balanced: + * On one hand, the time required for the statistical evaluation should not take too long. + * Therefore you will probably use a larger number of threads because most of its life time a thread will just wait for the database to return query results. + * On the other hand, the load on the database generated by all these threads should be limited so that the responsiveness of the production system is not affected. + * With a TimedSemaphore object this can be achieved. + * The semaphore can be configured to allow e.g. 100 queries per second. + * After these queries have been sent to the database the threads have to wait until the second is over - then they can query again. + * By fine-tuning the limit enforced by the semaphore a good balance between performance and database load can be established. + * It is even possible to chang? the number of available permits at runtime. + * So this number can be reduced during the typical working hours and increased at night.

              + * + *

              The following code examples demonstrate parts of the implementation of such a scenario. + * First the batch application has to create an instance of TimedSemaphore and to initialize its properties with default values:

              + * + * TimedSemaphore semaphore = new TimedSemaphore(1, TimeUnit.SECONDS, 100); + * + *

              Here we specify that the semaphore should allow 100 permits in one second. + * This is effectively the limit of database queries per second in our example use case. + * Next the server threads issuing database queries and performing statistical operations can be initialized. + * They are passed a reference to the semaphore at creation time. Before they execute a query they have to acquire a permit.

              + * + *
              + * 
              + * public class StatisticsTask implements Runnable {
              + * // The semaphore for limiting database load.
              + *   private final TimedSemaphore semaphore;
              + *
              + *   public StatisticsTask(TimedSemaphore sem, Connection con) {
              + *     semaphore = sem;
              + *      ...
              + *   }
              + *
              + *   //The main processing method. Executes queries and evaluates their results.
              + *   public void run() {
              + *     try {
              + *       while (!isDone()) {
              + *         semaphore.acquire();    // enforce the load limit
              + *         executeAndEvaluateQuery();
              + *       }
              + *     } catch (InterruptedException iex) {
              + *       // fall through
              + *     }
              + *   }
              + * }
              + * 
              + * 
              + * + *

              The important line here is the call to semaphore.acquire(). + * If the number of permits in the current time frame has not yet been reached, the call returns immediately. + * Otherwise, it blocks until the end of the time frame. + * The last piece missing is a scheduler service which adapts the number of permits allowed by the semaphore according to the time of day. + * We assume that this service is pretty simple and knows only two different time slots: + * working shift and night shift. + * The service is triggered periodically. + * It then determines the current time slot and configures the timed semaphore accordingly.

              + * + *
              + * 
              + * public class SchedulerService {
              + *   // The semaphore for limiting database load.
              + *   private final TimedSemaphore semaphore;
              + *     ...
              + *
              + *   // Configures the timed semaphore based on the current time of day. This method is called periodically.
              + *   public void configureTimedSemaphore() {
              + *      int limit;
              + *      if (isWorkshift()) {
              + *        limit = 50;    // low database load
              + *      } else {
              + *        limit = 250;   // high database load
              + *      }
              + *
              + *      semaphore.setLimit(limit);
              + *   }
              + * }
              + * 
              + * 
              + * + *

              With the {@link org.apache.commons.lang3.concurrent.TimedSemaphore#setLimit(int)} method the number of permits allowed for a time frame can be changed. + * There are some other methods for querying the internal state of a timed semaphore. + * Also some statistical data is available, e.g. the average number of acquire() calls per time frame. + * When a timed semaphore is no more needed, its shutdown() method has to be called.

              + */ +package org.apache.commons.lang3.concurrent; diff --git a/src/org/apache/commons/lang3/event/EventListenerSupport.java b/src/org/apache/commons/lang3/event/EventListenerSupport.java new file mode 100644 index 0000000..5e9a784 --- /dev/null +++ b/src/org/apache/commons/lang3/event/EventListenerSupport.java @@ -0,0 +1,340 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.event; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.commons.lang3.Validate; + +/** + *

              An EventListenerSupport object can be used to manage a list of event + * listeners of a particular type. The class provides + * {@link #addListener(Object)} and {@link #removeListener(Object)} methods + * for registering listeners, as well as a {@link #fire()} method for firing + * events to the listeners. + *

              + * + *

              + * To use this class, suppose you want to support ActionEvents. You would do: + *

              + *
              
              + * public class MyActionEventSource
              + * {
              + *   private EventListenerSupport<ActionListener> actionListeners =
              + *       EventListenerSupport.create(ActionListener.class);
              + *
              + *   public void someMethodThatFiresAction()
              + *   {
              + *     ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "somethingCool");
              + *     actionListeners.fire().actionPerformed(e);
              + *   }
              + * }
              + * 
              + * + *

              + * Serializing an {@link EventListenerSupport} instance will result in any + * non-{@link Serializable} listeners being silently dropped. + *

              + * + * @param the type of event listener that is supported by this proxy. + * + * @since 3.0 + */ +public class EventListenerSupport implements Serializable { + + /** Serialization version */ + private static final long serialVersionUID = 3593265990380473632L; + + /** + * The list used to hold the registered listeners. This list is + * intentionally a thread-safe copy-on-write-array so that traversals over + * the list of listeners will be atomic. + */ + private List listeners = new CopyOnWriteArrayList<>(); + + /** + * The proxy representing the collection of listeners. Calls to this proxy + * object will sent to all registered listeners. + */ + private transient L proxy; + + /** + * Empty typed array for #getListeners(). + */ + private transient L[] prototypeArray; + + /** + * Creates an EventListenerSupport object which supports the specified + * listener type. + * + * @param the type of the listener interface + * @param listenerInterface the type of listener interface that will receive + * events posted using this class. + * + * @return an EventListenerSupport object which supports the specified + * listener type. + * + * @throws NullPointerException if listenerInterface is + * null. + * @throws IllegalArgumentException if listenerInterface is + * not an interface. + */ + public static EventListenerSupport create(final Class listenerInterface) { + return new EventListenerSupport<>(listenerInterface); + } + + /** + * Creates an EventListenerSupport object which supports the provided + * listener interface. + * + * @param listenerInterface the type of listener interface that will receive + * events posted using this class. + * + * @throws NullPointerException if listenerInterface is + * null. + * @throws IllegalArgumentException if listenerInterface is + * not an interface. + */ + public EventListenerSupport(final Class listenerInterface) { + this(listenerInterface, Thread.currentThread().getContextClassLoader()); + } + + /** + * Creates an EventListenerSupport object which supports the provided + * listener interface using the specified class loader to create the JDK + * dynamic proxy. + * + * @param listenerInterface the listener interface. + * @param classLoader the class loader. + * + * @throws NullPointerException if listenerInterface or + * classLoader is null. + * @throws IllegalArgumentException if listenerInterface is + * not an interface. + */ + public EventListenerSupport(final Class listenerInterface, final ClassLoader classLoader) { + this(); + Validate.notNull(listenerInterface, "Listener interface cannot be null."); + Validate.notNull(classLoader, "ClassLoader cannot be null."); + Validate.isTrue(listenerInterface.isInterface(), "Class {0} is not an interface", + listenerInterface.getName()); + initializeTransientFields(listenerInterface, classLoader); + } + + /** + * Create a new EventListenerSupport instance. + * Serialization-friendly constructor. + */ + private EventListenerSupport() { + } + + /** + * Returns a proxy object which can be used to call listener methods on all + * of the registered event listeners. All calls made to this proxy will be + * forwarded to all registered listeners. + * + * @return a proxy object which can be used to call listener methods on all + * of the registered event listeners + */ + public L fire() { + return proxy; + } + +//********************************************************************************************************************** +// Other Methods +//********************************************************************************************************************** + + /** + * Registers an event listener. + * + * @param listener the event listener (may not be null). + * + * @throws NullPointerException if listener is + * null. + */ + public void addListener(final L listener) { + addListener(listener, true); + } + + /** + * Registers an event listener. Will not add a pre-existing listener + * object to the list if allowDuplicate is false. + * + * @param listener the event listener (may not be null). + * @param allowDuplicate the flag for determining if duplicate listener + * objects are allowed to be registered. + * + * @throws NullPointerException if listener is null. + * @since 3.5 + */ + public void addListener(final L listener, final boolean allowDuplicate) { + Validate.notNull(listener, "Listener object cannot be null."); + if (allowDuplicate) { + listeners.add(listener); + } else if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + /** + * Returns the number of registered listeners. + * + * @return the number of registered listeners. + */ + int getListenerCount() { + return listeners.size(); + } + + /** + * Unregisters an event listener. + * + * @param listener the event listener (may not be null). + * + * @throws NullPointerException if listener is + * null. + */ + public void removeListener(final L listener) { + Validate.notNull(listener, "Listener object cannot be null."); + listeners.remove(listener); + } + + /** + * Get an array containing the currently registered listeners. + * Modification to this array's elements will have no effect on the + * {@link EventListenerSupport} instance. + * @return L[] + */ + public L[] getListeners() { + return listeners.toArray(prototypeArray); + } + + /** + * Serialize. + * @param objectOutputStream the output stream + * @throws IOException if an IO error occurs + */ + private void writeObject(final ObjectOutputStream objectOutputStream) throws IOException { + final ArrayList serializableListeners = new ArrayList<>(); + + // don't just rely on instanceof Serializable: + ObjectOutputStream testObjectOutputStream = new ObjectOutputStream(new ByteArrayOutputStream()); + for (final L listener : listeners) { + try { + testObjectOutputStream.writeObject(listener); + serializableListeners.add(listener); + } catch (final IOException exception) { + //recreate test stream in case of indeterminate state + testObjectOutputStream = new ObjectOutputStream(new ByteArrayOutputStream()); + } + } + /* + * we can reconstitute everything we need from an array of our listeners, + * which has the additional advantage of typically requiring less storage than a list: + */ + objectOutputStream.writeObject(serializableListeners.toArray(prototypeArray)); + } + + /** + * Deserialize. + * @param objectInputStream the input stream + * @throws IOException if an IO error occurs + * @throws ClassNotFoundException if the class cannot be resolved + */ + private void readObject(final ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException { + @SuppressWarnings("unchecked") // Will throw CCE here if not correct + final + L[] srcListeners = (L[]) objectInputStream.readObject(); + + this.listeners = new CopyOnWriteArrayList<>(srcListeners); + + @SuppressWarnings("unchecked") // Will throw CCE here if not correct + final + Class listenerInterface = (Class) srcListeners.getClass().getComponentType(); + + initializeTransientFields(listenerInterface, Thread.currentThread().getContextClassLoader()); + } + + /** + * Initialize transient fields. + * @param listenerInterface the class of the listener interface + * @param classLoader the class loader to be used + */ + private void initializeTransientFields(final Class listenerInterface, final ClassLoader classLoader) { + @SuppressWarnings("unchecked") // Will throw CCE here if not correct + final + L[] array = (L[]) Array.newInstance(listenerInterface, 0); + this.prototypeArray = array; + createProxy(listenerInterface, classLoader); + } + + /** + * Create the proxy object. + * @param listenerInterface the class of the listener interface + * @param classLoader the class loader to be used + */ + private void createProxy(final Class listenerInterface, final ClassLoader classLoader) { + proxy = listenerInterface.cast(Proxy.newProxyInstance(classLoader, + new Class[] { listenerInterface }, createInvocationHandler())); + } + + /** + * Create the {@link InvocationHandler} responsible for broadcasting calls + * to the managed listeners. Subclasses can override to provide custom behavior. + * @return ProxyInvocationHandler + */ + protected InvocationHandler createInvocationHandler() { + return new ProxyInvocationHandler(); + } + + /** + * An invocation handler used to dispatch the event(s) to all the listeners. + */ + protected class ProxyInvocationHandler implements InvocationHandler { + + /** + * Propagates the method call to all registered listeners in place of + * the proxy listener object. + * + * @param unusedProxy the proxy object representing a listener on which the + * invocation was called; not used + * @param method the listener method that will be called on all of the + * listeners. + * @param args event arguments to propagate to the listeners. + * @return the result of the method call + * @throws Throwable if an error occurs + */ + @Override + public Object invoke(final Object unusedProxy, final Method method, final Object[] args) throws Throwable { + for (final L listener : listeners) { + method.invoke(listener, args); + } + return null; + } + } +} diff --git a/src/org/apache/commons/lang3/event/EventUtils.java b/src/org/apache/commons/lang3/event/EventUtils.java new file mode 100644 index 0000000..c5baf62 --- /dev/null +++ b/src/org/apache/commons/lang3/event/EventUtils.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.event; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang3.reflect.MethodUtils; + +/** + * Provides some useful event-based utility methods. + * + * @since 3.0 + */ +public class EventUtils { + + /** + * Adds an event listener to the specified source. This looks for an "add" method corresponding to the event + * type (addActionListener, for example). + * @param eventSource the event source + * @param listenerType the event listener type + * @param listener the listener + * @param the event listener type + * + * @throws IllegalArgumentException if the object doesn't support the listener type + */ + public static void addEventListener(final Object eventSource, final Class listenerType, final L listener) { + try { + MethodUtils.invokeMethod(eventSource, "add" + listenerType.getSimpleName(), listener); + } catch (final NoSuchMethodException e) { + throw new IllegalArgumentException("Class " + eventSource.getClass().getName() + + " does not have a public add" + listenerType.getSimpleName() + + " method which takes a parameter of type " + listenerType.getName() + "."); + } catch (final IllegalAccessException e) { + throw new IllegalArgumentException("Class " + eventSource.getClass().getName() + + " does not have an accessible add" + listenerType.getSimpleName () + + " method which takes a parameter of type " + listenerType.getName() + "."); + } catch (final InvocationTargetException e) { + throw new RuntimeException("Unable to add listener.", e.getCause()); + } + } + + /** + * Binds an event listener to a specific method on a specific object. + * + * @param the event listener type + * @param target the target object + * @param methodName the name of the method to be called + * @param eventSource the object which is generating events (JButton, JList, etc.) + * @param listenerType the listener interface (ActionListener.class, SelectionListener.class, etc.) + * @param eventTypes the event types (method names) from the listener interface (if none specified, all will be + * supported) + */ + public static void bindEventsToMethod(final Object target, final String methodName, final Object eventSource, + final Class listenerType, final String... eventTypes) { + final L listener = listenerType.cast(Proxy.newProxyInstance(target.getClass().getClassLoader(), + new Class[] { listenerType }, new EventBindingInvocationHandler(target, methodName, eventTypes))); + addEventListener(eventSource, listenerType, listener); + } + + private static class EventBindingInvocationHandler implements InvocationHandler { + private final Object target; + private final String methodName; + private final Set eventTypes; + + /** + * Creates a new instance of {@code EventBindingInvocationHandler}. + * + * @param target the target object for method invocations + * @param methodName the name of the method to be invoked + * @param eventTypes the names of the supported event types + */ + EventBindingInvocationHandler(final Object target, final String methodName, final String[] eventTypes) { + this.target = target; + this.methodName = methodName; + this.eventTypes = new HashSet<>(Arrays.asList(eventTypes)); + } + + /** + * Handles a method invocation on the proxy object. + * + * @param proxy the proxy instance + * @param method the method to be invoked + * @param parameters the parameters for the method invocation + * @return the result of the method call + * @throws Throwable if an error occurs + */ + @Override + public Object invoke(final Object proxy, final Method method, final Object[] parameters) throws Throwable { + if (eventTypes.isEmpty() || eventTypes.contains(method.getName())) { + if (hasMatchingParametersMethod(method)) { + return MethodUtils.invokeMethod(target, methodName, parameters); + } + return MethodUtils.invokeMethod(target, methodName); + } + return null; + } + + /** + * Checks whether a method for the passed in parameters can be found. + * + * @param method the listener method invoked + * @return a flag whether the parameters could be matched + */ + private boolean hasMatchingParametersMethod(final Method method) { + return MethodUtils.getAccessibleMethod(target.getClass(), methodName, method.getParameterTypes()) != null; + } + } +} diff --git a/src/org/apache/commons/lang3/event/package-info.java b/src/org/apache/commons/lang3/event/package-info.java new file mode 100644 index 0000000..0227a16 --- /dev/null +++ b/src/org/apache/commons/lang3/event/package-info.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Provides some useful event-based utilities. + * + * @since 3.0 + */ +package org.apache.commons.lang3.event; diff --git a/src/org/apache/commons/lang3/exception/CloneFailedException.java b/src/org/apache/commons/lang3/exception/CloneFailedException.java new file mode 100644 index 0000000..138b250 --- /dev/null +++ b/src/org/apache/commons/lang3/exception/CloneFailedException.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.exception; + +/** + * Exception thrown when a clone cannot be created. In contrast to + * {@link CloneNotSupportedException} this is a {@link RuntimeException}. + * + * @since 3.0 + */ +public class CloneFailedException extends RuntimeException { + // ~ Static fields/initializers --------------------------------------------- + + private static final long serialVersionUID = 20091223L; + + // ~ Constructors ----------------------------------------------------------- + + /** + * Constructs a CloneFailedException. + * + * @param message description of the exception + * @since upcoming + */ + public CloneFailedException(final String message) { + super(message); + } + + /** + * Constructs a CloneFailedException. + * + * @param cause cause of the exception + * @since upcoming + */ + public CloneFailedException(final Throwable cause) { + super(cause); + } + + /** + * Constructs a CloneFailedException. + * + * @param message description of the exception + * @param cause cause of the exception + * @since upcoming + */ + public CloneFailedException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/org/apache/commons/lang3/exception/ContextedException.java b/src/org/apache/commons/lang3/exception/ContextedException.java new file mode 100644 index 0000000..326152a --- /dev/null +++ b/src/org/apache/commons/lang3/exception/ContextedException.java @@ -0,0 +1,256 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.exception; + +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.tuple.Pair; + +/** + *

              + * An exception that provides an easy and safe way to add contextual information. + *

              + * An exception trace itself is often insufficient to provide rapid diagnosis of the issue. + * Frequently what is needed is a select few pieces of local contextual data. + * Providing this data is tricky however, due to concerns over formatting and nulls. + *

              + * The contexted exception approach allows the exception to be created together with a + * list of context label-value pairs. This additional information is automatically included in + * the message and printed stack trace. + *

              + * An unchecked version of this exception is provided by ContextedRuntimeException. + *

              + *

              + * To use this class write code as follows: + *

              + *
              + *   try {
              + *     ...
              + *   } catch (Exception e) {
              + *     throw new ContextedException("Error posting account transaction", e)
              + *          .addContextValue("Account Number", accountNumber)
              + *          .addContextValue("Amount Posted", amountPosted)
              + *          .addContextValue("Previous Balance", previousBalance)
              + *   }
              + * }
              + * 
              + *

              + * or improve diagnose data at a higher level: + *

              + *
              + *   try {
              + *     ...
              + *   } catch (ContextedException e) {
              + *     throw e.setContextValue("Transaction Id", transactionId);
              + *   } catch (Exception e) {
              + *     if (e instanceof ExceptionContext) {
              + *       e.setContextValue("Transaction Id", transactionId);
              + *     }
              + *     throw e;
              + *   }
              + * }
              + * 
              + *

              + * The output in a printStacktrace() (which often is written to a log) would look something like the following: + *

              + *
              + * org.apache.commons.lang3.exception.ContextedException: java.lang.Exception: Error posting account transaction
              + *  Exception Context:
              + *  [1:Account Number=null]
              + *  [2:Amount Posted=100.00]
              + *  [3:Previous Balance=-2.17]
              + *  [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899]
              + *
              + *  ---------------------------------
              + *  at org.apache.commons.lang3.exception.ContextedExceptionTest.testAddValue(ContextedExceptionTest.java:88)
              + *  ..... (rest of trace)
              + * 
              + * + * @see ContextedRuntimeException + * @since 3.0 + */ +public class ContextedException extends Exception implements ExceptionContext { + + /** The serialization version. */ + private static final long serialVersionUID = 20110706L; + /** The context where the data is stored. */ + private final ExceptionContext exceptionContext; + + /** + * Instantiates ContextedException without message or cause. + *

              + * The context information is stored using a default implementation. + */ + public ContextedException() { + super(); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with message, but without cause. + *

              + * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + */ + public ContextedException(final String message) { + super(message); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with cause, but without message. + *

              + * The context information is stored using a default implementation. + * + * @param cause the underlying cause of the exception, may be null + */ + public ContextedException(final Throwable cause) { + super(cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with cause and message. + *

              + * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + */ + public ContextedException(final String message, final Throwable cause) { + super(message, cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedException with cause, message, and ExceptionContext. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + * @param context the context used to store the additional information, null uses default implementation + */ + public ContextedException(final String message, final Throwable cause, ExceptionContext context) { + super(message, cause); + if (context == null) { + context = new DefaultExceptionContext(); + } + exceptionContext = context; + } + + //----------------------------------------------------------------------- + /** + * Adds information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Different values can be added with the same label multiple times. + *

              + * Note: This exception is only serializable if the object added is serializable. + *

              + * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + @Override + public ContextedException addContextValue(final String label, final Object value) { + exceptionContext.addContextValue(label, value); + return this; + } + + /** + * Sets information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Any existing values with the same labels are removed before the new one is added. + *

              + * Note: This exception is only serializable if the object added as value is serializable. + *

              + * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + @Override + public ContextedException setContextValue(final String label, final Object value) { + exceptionContext.setContextValue(label, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public List getContextValues(final String label) { + return this.exceptionContext.getContextValues(label); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getFirstContextValue(final String label) { + return this.exceptionContext.getFirstContextValue(label); + } + + /** + * {@inheritDoc} + */ + @Override + public List> getContextEntries() { + return this.exceptionContext.getContextEntries(); + } + + /** + * {@inheritDoc} + */ + @Override + public Set getContextLabels() { + return exceptionContext.getContextLabels(); + } + + /** + * Provides the message explaining the exception, including the contextual data. + * + * @see java.lang.Throwable#getMessage() + * @return the message, never null + */ + @Override + public String getMessage(){ + return getFormattedExceptionMessage(super.getMessage()); + } + + /** + * Provides the message explaining the exception without the contextual data. + * + * @see java.lang.Throwable#getMessage() + * @return the message + * @since 3.0.1 + */ + public String getRawMessage() { + return super.getMessage(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getFormattedExceptionMessage(final String baseMessage) { + return exceptionContext.getFormattedExceptionMessage(baseMessage); + } +} diff --git a/src/org/apache/commons/lang3/exception/ContextedRuntimeException.java b/src/org/apache/commons/lang3/exception/ContextedRuntimeException.java new file mode 100644 index 0000000..0120883 --- /dev/null +++ b/src/org/apache/commons/lang3/exception/ContextedRuntimeException.java @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.exception; + +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.tuple.Pair; + +/** + *

              + * A runtime exception that provides an easy and safe way to add contextual information. + *

              + * An exception trace itself is often insufficient to provide rapid diagnosis of the issue. + * Frequently what is needed is a select few pieces of local contextual data. + * Providing this data is tricky however, due to concerns over formatting and nulls. + *

              + * The contexted exception approach allows the exception to be created together with a + * list of context label-value pairs. This additional information is automatically included in + * the message and printed stack trace. + *

              + * A checked version of this exception is provided by ContextedException. + *

              + *

              + * To use this class write code as follows: + *

              + *
              + *   try {
              + *     ...
              + *   } catch (Exception e) {
              + *     throw new ContextedRuntimeException("Error posting account transaction", e)
              + *          .addContextValue("Account Number", accountNumber)
              + *          .addContextValue("Amount Posted", amountPosted)
              + *          .addContextValue("Previous Balance", previousBalance)
              + *   }
              + * }
              + * 
              + *

              + * or improve diagnose data at a higher level: + *

              + *
              + *   try {
              + *     ...
              + *   } catch (ContextedRuntimeException e) {
              + *     throw e.setContextValue("Transaction Id", transactionId);
              + *   } catch (Exception e) {
              + *     if (e instanceof ExceptionContext) {
              + *       e.setContextValue("Transaction Id", transactionId);
              + *     }
              + *     throw e;
              + *   }
              + * }
              + * 
              + *

              + * The output in a printStacktrace() (which often is written to a log) would look something like the following: + *

              + *
              + * org.apache.commons.lang3.exception.ContextedRuntimeException: java.lang.Exception: Error posting account transaction
              + *  Exception Context:
              + *  [1:Account Number=null]
              + *  [2:Amount Posted=100.00]
              + *  [3:Previous Balance=-2.17]
              + *  [4:Transaction Id=94ef1d15-d443-46c4-822b-637f26244899]
              + *
              + *  ---------------------------------
              + *  at org.apache.commons.lang3.exception.ContextedRuntimeExceptionTest.testAddValue(ContextedExceptionTest.java:88)
              + *  ..... (rest of trace)
              + * 
              + * + * @see ContextedException + * @since 3.0 + */ +public class ContextedRuntimeException extends RuntimeException implements ExceptionContext { + + /** The serialization version. */ + private static final long serialVersionUID = 20110706L; + /** The context where the data is stored. */ + private final ExceptionContext exceptionContext; + + /** + * Instantiates ContextedRuntimeException without message or cause. + *

              + * The context information is stored using a default implementation. + */ + public ContextedRuntimeException() { + super(); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with message, but without cause. + *

              + * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + */ + public ContextedRuntimeException(final String message) { + super(message); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with cause, but without message. + *

              + * The context information is stored using a default implementation. + * + * @param cause the underlying cause of the exception, may be null + */ + public ContextedRuntimeException(final Throwable cause) { + super(cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with cause and message. + *

              + * The context information is stored using a default implementation. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + */ + public ContextedRuntimeException(final String message, final Throwable cause) { + super(message, cause); + exceptionContext = new DefaultExceptionContext(); + } + + /** + * Instantiates ContextedRuntimeException with cause, message, and ExceptionContext. + * + * @param message the exception message, may be null + * @param cause the underlying cause of the exception, may be null + * @param context the context used to store the additional information, null uses default implementation + */ + public ContextedRuntimeException(final String message, final Throwable cause, ExceptionContext context) { + super(message, cause); + if (context == null) { + context = new DefaultExceptionContext(); + } + exceptionContext = context; + } + + //----------------------------------------------------------------------- + /** + * Adds information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Different values can be added with the same label multiple times. + *

              + * Note: This exception is only serializable if the object added is serializable. + *

              + * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + @Override + public ContextedRuntimeException addContextValue(final String label, final Object value) { + exceptionContext.addContextValue(label, value); + return this; + } + + /** + * Sets information helpful to a developer in diagnosing and correcting the problem. + * For the information to be meaningful, the value passed should have a reasonable + * toString() implementation. + * Any existing values with the same labels are removed before the new one is added. + *

              + * Note: This exception is only serializable if the object added as value is serializable. + *

              + * + * @param label a textual label associated with information, {@code null} not recommended + * @param value information needed to understand exception, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + @Override + public ContextedRuntimeException setContextValue(final String label, final Object value) { + exceptionContext.setContextValue(label, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public List getContextValues(final String label) { + return this.exceptionContext.getContextValues(label); + } + + /** + * {@inheritDoc} + */ + @Override + public Object getFirstContextValue(final String label) { + return this.exceptionContext.getFirstContextValue(label); + } + + /** + * {@inheritDoc} + */ + @Override + public List> getContextEntries() { + return this.exceptionContext.getContextEntries(); + } + + /** + * {@inheritDoc} + */ + @Override + public Set getContextLabels() { + return exceptionContext.getContextLabels(); + } + + /** + * Provides the message explaining the exception, including the contextual data. + * + * @see java.lang.Throwable#getMessage() + * @return the message, never null + */ + @Override + public String getMessage(){ + return getFormattedExceptionMessage(super.getMessage()); + } + + /** + * Provides the message explaining the exception without the contextual data. + * + * @see java.lang.Throwable#getMessage() + * @return the message + * @since 3.0.1 + */ + public String getRawMessage() { + return super.getMessage(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getFormattedExceptionMessage(final String baseMessage) { + return exceptionContext.getFormattedExceptionMessage(baseMessage); + } + +} diff --git a/src/org/apache/commons/lang3/exception/DefaultExceptionContext.java b/src/org/apache/commons/lang3/exception/DefaultExceptionContext.java new file mode 100644 index 0000000..17d98a4 --- /dev/null +++ b/src/org/apache/commons/lang3/exception/DefaultExceptionContext.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.exception; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +/** + * Default implementation of the context storing the label-value pairs for contexted exceptions. + *

              + * This implementation is serializable, however this is dependent on the values that + * are added also being serializable. + *

              + * + * @see ContextedException + * @see ContextedRuntimeException + * @since 3.0 + */ +public class DefaultExceptionContext implements ExceptionContext, Serializable { + + /** The serialization version. */ + private static final long serialVersionUID = 20110706L; + + /** The list storing the label-data pairs. */ + private final List> contextValues = new ArrayList<>(); + + /** + * {@inheritDoc} + */ + @Override + public DefaultExceptionContext addContextValue(final String label, final Object value) { + contextValues.add(new ImmutablePair<>(label, value)); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public DefaultExceptionContext setContextValue(final String label, final Object value) { + for (final Iterator> iter = contextValues.iterator(); iter.hasNext();) { + final Pair p = iter.next(); + if (StringUtils.equals(label, p.getKey())) { + iter.remove(); + } + } + addContextValue(label, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public List getContextValues(final String label) { + final List values = new ArrayList<>(); + for (final Pair pair : contextValues) { + if (StringUtils.equals(label, pair.getKey())) { + values.add(pair.getValue()); + } + } + return values; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getFirstContextValue(final String label) { + for (final Pair pair : contextValues) { + if (StringUtils.equals(label, pair.getKey())) { + return pair.getValue(); + } + } + return null; + } + + /** + * {@inheritDoc} + */ + @Override + public Set getContextLabels() { + final Set labels = new HashSet<>(); + for (final Pair pair : contextValues) { + labels.add(pair.getKey()); + } + return labels; + } + + /** + * {@inheritDoc} + */ + @Override + public List> getContextEntries() { + return contextValues; + } + + /** + * Builds the message containing the contextual information. + * + * @param baseMessage the base exception message without context information appended + * @return the exception message with context information appended, never null + */ + @Override + public String getFormattedExceptionMessage(final String baseMessage){ + final StringBuilder buffer = new StringBuilder(256); + if (baseMessage != null) { + buffer.append(baseMessage); + } + + if (contextValues.size() > 0) { + if (buffer.length() > 0) { + buffer.append('\n'); + } + buffer.append("Exception Context:\n"); + + int i = 0; + for (final Pair pair : contextValues) { + buffer.append("\t["); + buffer.append(++i); + buffer.append(':'); + buffer.append(pair.getKey()); + buffer.append("="); + final Object value = pair.getValue(); + if (value == null) { + buffer.append("null"); + } else { + String valueStr; + try { + valueStr = value.toString(); + } catch (final Exception e) { + valueStr = "Exception thrown on toString(): " + ExceptionUtils.getStackTrace(e); + } + buffer.append(valueStr); + } + buffer.append("]\n"); + } + buffer.append("---------------------------------"); + } + return buffer.toString(); + } + +} diff --git a/src/org/apache/commons/lang3/exception/ExceptionContext.java b/src/org/apache/commons/lang3/exception/ExceptionContext.java new file mode 100644 index 0000000..1e84659 --- /dev/null +++ b/src/org/apache/commons/lang3/exception/ExceptionContext.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.exception; + +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.tuple.Pair; + +/** + * Allows the storage and retrieval of contextual information based on label-value + * pairs for exceptions. + *

              + * Implementations are expected to manage the pairs in a list-style collection + * that keeps the pairs in the sequence of their addition. + *

              + * + * @see ContextedException + * @see ContextedRuntimeException + * @since 3.0 + */ +public interface ExceptionContext { + + /** + * Adds a contextual label-value pair into this context. + *

              + * The pair will be added to the context, independently of an already + * existing pair with the same label. + *

              + * + * @param label the label of the item to add, {@code null} not recommended + * @param value the value of item to add, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + ExceptionContext addContextValue(String label, Object value); + + /** + * Sets a contextual label-value pair into this context. + *

              + * The pair will be added normally, but any existing label-value pair with + * the same label is removed from the context. + *

              + * + * @param label the label of the item to add, {@code null} not recommended + * @param value the value of item to add, may be {@code null} + * @return {@code this}, for method chaining, not {@code null} + */ + ExceptionContext setContextValue(String label, Object value); + + /** + * Retrieves all the contextual data values associated with the label. + * + * @param label the label to get the contextual values for, may be {@code null} + * @return the contextual values associated with the label, never {@code null} + */ + List getContextValues(String label); + + /** + * Retrieves the first available contextual data value associated with the label. + * + * @param label the label to get the contextual value for, may be {@code null} + * @return the first contextual value associated with the label, may be {@code null} + */ + Object getFirstContextValue(String label); + + /** + * Retrieves the full set of labels defined in the contextual data. + * + * @return the set of labels, not {@code null} + */ + Set getContextLabels(); + + /** + * Retrieves the full list of label-value pairs defined in the contextual data. + * + * @return the list of pairs, not {@code null} + */ + List> getContextEntries(); + + /** + * Gets the contextualized error message based on a base message. + * This will add the context label-value pairs to the message. + * + * @param baseMessage the base exception message without context information appended + * @return the exception message with context information appended, not {@code null} + */ + String getFormattedExceptionMessage(String baseMessage); + +} diff --git a/src/org/apache/commons/lang3/exception/ExceptionUtils.java b/src/org/apache/commons/lang3/exception/ExceptionUtils.java new file mode 100644 index 0000000..39e270b --- /dev/null +++ b/src/org/apache/commons/lang3/exception/ExceptionUtils.java @@ -0,0 +1,817 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.exception; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; + +/** + *

              Provides utilities for manipulating and examining + * Throwable objects.

              + * + * @since 1.0 + */ +public class ExceptionUtils { + + /** + *

              Used when printing stack frames to denote the start of a + * wrapped exception.

              + * + *

              Package private for accessibility by test suite.

              + */ + static final String WRAPPED_MARKER = " [wrapped] "; + + /** + *

              The names of methods commonly used to access a wrapped exception.

              + */ + // TODO: Remove in Lang 4.0 + private static final String[] CAUSE_METHOD_NAMES = { + "getCause", + "getNextException", + "getTargetException", + "getException", + "getSourceException", + "getRootCause", + "getCausedByException", + "getNested", + "getLinkedException", + "getNestedException", + "getLinkedCause", + "getThrowable", + }; + + /** + *

              + * Public constructor allows an instance of ExceptionUtils to be created, although that is not + * normally necessary. + *

              + */ + public ExceptionUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

              Returns the default names used when searching for the cause of an exception.

              + * + *

              This may be modified and used in the overloaded getCause(Throwable, String[]) method.

              + * + * @return cloned array of the default method names + * @since 3.0 + * @deprecated This feature will be removed in Lang 4.0 + */ + @Deprecated + public static String[] getDefaultCauseMethodNames() { + return ArrayUtils.clone(CAUSE_METHOD_NAMES); + } + + //----------------------------------------------------------------------- + /** + *

              Introspects the Throwable to obtain the cause.

              + * + *

              The method searches for methods with specific names that return a + * Throwable object. This will pick up most wrapping exceptions, + * including those from JDK 1.4. + * + *

              The default list searched for are:

              + *
                + *
              • getCause()
              • + *
              • getNextException()
              • + *
              • getTargetException()
              • + *
              • getException()
              • + *
              • getSourceException()
              • + *
              • getRootCause()
              • + *
              • getCausedByException()
              • + *
              • getNested()
              • + *
              + * + *

              If none of the above is found, returns null.

              + * + * @param throwable the throwable to introspect for a cause, may be null + * @return the cause of the Throwable, + * null if none found or null throwable input + * @since 1.0 + * @deprecated This feature will be removed in Lang 4.0, use {@link Throwable#getCause} instead + */ + @Deprecated + public static Throwable getCause(final Throwable throwable) { + return getCause(throwable, null); + } + + /** + *

              Introspects the Throwable to obtain the cause.

              + * + *

              A null set of method names means use the default set. + * A null in the set of method names will be ignored.

              + * + * @param throwable the throwable to introspect for a cause, may be null + * @param methodNames the method names, null treated as default set + * @return the cause of the Throwable, + * null if none found or null throwable input + * @since 1.0 + * @deprecated This feature will be removed in Lang 4.0, use {@link Throwable#getCause} instead + */ + @Deprecated + public static Throwable getCause(final Throwable throwable, String[] methodNames) { + if (throwable == null) { + return null; + } + + if (methodNames == null) { + final Throwable cause = throwable.getCause(); + if (cause != null) { + return cause; + } + + methodNames = CAUSE_METHOD_NAMES; + } + + for (final String methodName : methodNames) { + if (methodName != null) { + final Throwable legacyCause = getCauseUsingMethodName(throwable, methodName); + if (legacyCause != null) { + return legacyCause; + } + } + } + + return null; + } + + /** + *

              Introspects the Throwable to obtain the root cause.

              + * + *

              This method walks through the exception chain to the last element, + * "root" of the tree, using {@link #getCause(Throwable)}, and + * returns that exception.

              + * + *

              From version 2.2, this method handles recursive cause structures + * that might otherwise cause infinite loops. If the throwable parameter + * has a cause of itself, then null will be returned. If the throwable + * parameter cause chain loops, the last element in the chain before the + * loop is returned.

              + * + * @param throwable the throwable to get the root cause for, may be null + * @return the root cause of the Throwable, + * null if none found or null throwable input + */ + public static Throwable getRootCause(final Throwable throwable) { + final List list = getThrowableList(throwable); + return list.size() < 2 ? null : list.get(list.size() - 1); + } + + /** + *

              Finds a Throwable by method name.

              + * + * @param throwable the exception to examine + * @param methodName the name of the method to find and invoke + * @return the wrapped exception, or null if not found + */ + // TODO: Remove in Lang 4.0 + private static Throwable getCauseUsingMethodName(final Throwable throwable, final String methodName) { + Method method = null; + try { + method = throwable.getClass().getMethod(methodName); + } catch (final NoSuchMethodException | SecurityException ignored) { // NOPMD + // exception ignored + } + + if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) { + try { + return (Throwable) method.invoke(throwable); + } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException ignored) { // NOPMD + // exception ignored + } + } + return null; + } + + //----------------------------------------------------------------------- + /** + *

              Counts the number of Throwable objects in the + * exception chain.

              + * + *

              A throwable without cause will return 1. + * A throwable with one cause will return 2 and so on. + * A null throwable will return 0.

              + * + *

              From version 2.2, this method handles recursive cause structures + * that might otherwise cause infinite loops. The cause chain is + * processed until the end is reached, or until the next item in the + * chain is already in the result set.

              + * + * @param throwable the throwable to inspect, may be null + * @return the count of throwables, zero if null input + */ + public static int getThrowableCount(final Throwable throwable) { + return getThrowableList(throwable).size(); + } + + /** + *

              Returns the list of Throwable objects in the + * exception chain.

              + * + *

              A throwable without cause will return an array containing + * one element - the input throwable. + * A throwable with one cause will return an array containing + * two elements. - the input throwable and the cause throwable. + * A null throwable will return an array of size zero.

              + * + *

              From version 2.2, this method handles recursive cause structures + * that might otherwise cause infinite loops. The cause chain is + * processed until the end is reached, or until the next item in the + * chain is already in the result set.

              + * + * @see #getThrowableList(Throwable) + * @param throwable the throwable to inspect, may be null + * @return the array of throwables, never null + */ + public static Throwable[] getThrowables(final Throwable throwable) { + final List list = getThrowableList(throwable); + return list.toArray(new Throwable[list.size()]); + } + + /** + *

              Returns the list of Throwable objects in the + * exception chain.

              + * + *

              A throwable without cause will return a list containing + * one element - the input throwable. + * A throwable with one cause will return a list containing + * two elements. - the input throwable and the cause throwable. + * A null throwable will return a list of size zero.

              + * + *

              This method handles recursive cause structures that might + * otherwise cause infinite loops. The cause chain is processed until + * the end is reached, or until the next item in the chain is already + * in the result set.

              + * + * @param throwable the throwable to inspect, may be null + * @return the list of throwables, never null + * @since Commons Lang 2.2 + */ + public static List getThrowableList(Throwable throwable) { + final List list = new ArrayList<>(); + while (throwable != null && list.contains(throwable) == false) { + list.add(throwable); + throwable = ExceptionUtils.getCause(throwable); + } + return list; + } + + //----------------------------------------------------------------------- + /** + *

              Returns the (zero based) index of the first Throwable + * that matches the specified class (exactly) in the exception chain. + * Subclasses of the specified class do not match - see + * {@link #indexOfType(Throwable, Class)} for the opposite.

              + * + *

              A null throwable returns -1. + * A null type returns -1. + * No match in the chain returns -1.

              + * + * @param throwable the throwable to inspect, may be null + * @param clazz the class to search for, subclasses do not match, null returns -1 + * @return the index into the throwable chain, -1 if no match or null input + */ + public static int indexOfThrowable(final Throwable throwable, final Class clazz) { + return indexOf(throwable, clazz, 0, false); + } + + /** + *

              Returns the (zero based) index of the first Throwable + * that matches the specified type in the exception chain from + * a specified index. + * Subclasses of the specified class do not match - see + * {@link #indexOfType(Throwable, Class, int)} for the opposite.

              + * + *

              A null throwable returns -1. + * A null type returns -1. + * No match in the chain returns -1. + * A negative start index is treated as zero. + * A start index greater than the number of throwables returns -1.

              + * + * @param throwable the throwable to inspect, may be null + * @param clazz the class to search for, subclasses do not match, null returns -1 + * @param fromIndex the (zero based) index of the starting position, + * negative treated as zero, larger than chain size returns -1 + * @return the index into the throwable chain, -1 if no match or null input + */ + public static int indexOfThrowable(final Throwable throwable, final Class clazz, final int fromIndex) { + return indexOf(throwable, clazz, fromIndex, false); + } + + //----------------------------------------------------------------------- + /** + *

              Returns the (zero based) index of the first Throwable + * that matches the specified class or subclass in the exception chain. + * Subclasses of the specified class do match - see + * {@link #indexOfThrowable(Throwable, Class)} for the opposite.

              + * + *

              A null throwable returns -1. + * A null type returns -1. + * No match in the chain returns -1.

              + * + * @param throwable the throwable to inspect, may be null + * @param type the type to search for, subclasses match, null returns -1 + * @return the index into the throwable chain, -1 if no match or null input + * @since 2.1 + */ + public static int indexOfType(final Throwable throwable, final Class type) { + return indexOf(throwable, type, 0, true); + } + + /** + *

              Returns the (zero based) index of the first Throwable + * that matches the specified type in the exception chain from + * a specified index. + * Subclasses of the specified class do match - see + * {@link #indexOfThrowable(Throwable, Class)} for the opposite.

              + * + *

              A null throwable returns -1. + * A null type returns -1. + * No match in the chain returns -1. + * A negative start index is treated as zero. + * A start index greater than the number of throwables returns -1.

              + * + * @param throwable the throwable to inspect, may be null + * @param type the type to search for, subclasses match, null returns -1 + * @param fromIndex the (zero based) index of the starting position, + * negative treated as zero, larger than chain size returns -1 + * @return the index into the throwable chain, -1 if no match or null input + * @since 2.1 + */ + public static int indexOfType(final Throwable throwable, final Class type, final int fromIndex) { + return indexOf(throwable, type, fromIndex, true); + } + + /** + *

              Worker method for the indexOfType methods.

              + * + * @param throwable the throwable to inspect, may be null + * @param type the type to search for, subclasses match, null returns -1 + * @param fromIndex the (zero based) index of the starting position, + * negative treated as zero, larger than chain size returns -1 + * @param subclass if true, compares with {@link Class#isAssignableFrom(Class)}, otherwise compares + * using references + * @return index of the type within throwables nested within the specified throwable + */ + private static int indexOf(final Throwable throwable, final Class type, int fromIndex, final boolean subclass) { + if (throwable == null || type == null) { + return -1; + } + if (fromIndex < 0) { + fromIndex = 0; + } + final Throwable[] throwables = ExceptionUtils.getThrowables(throwable); + if (fromIndex >= throwables.length) { + return -1; + } + if (subclass) { + for (int i = fromIndex; i < throwables.length; i++) { + if (type.isAssignableFrom(throwables[i].getClass())) { + return i; + } + } + } else { + for (int i = fromIndex; i < throwables.length; i++) { + if (type.equals(throwables[i].getClass())) { + return i; + } + } + } + return -1; + } + + //----------------------------------------------------------------------- + /** + *

              Prints a compact stack trace for the root cause of a throwable + * to System.err.

              + * + *

              The compact stack trace starts with the root cause and prints + * stack frames up to the place where it was caught and wrapped. + * Then it prints the wrapped exception and continues with stack frames + * until the wrapper exception is caught and wrapped again, etc.

              + * + *

              The output of this method is consistent across JDK versions. + * Note that this is the opposite order to the JDK1.4 display.

              + * + *

              The method is equivalent to printStackTrace for throwables + * that don't have nested causes.

              + * + * @param throwable the throwable to output + * @since 2.0 + */ + public static void printRootCauseStackTrace(final Throwable throwable) { + printRootCauseStackTrace(throwable, System.err); + } + + /** + *

              Prints a compact stack trace for the root cause of a throwable.

              + * + *

              The compact stack trace starts with the root cause and prints + * stack frames up to the place where it was caught and wrapped. + * Then it prints the wrapped exception and continues with stack frames + * until the wrapper exception is caught and wrapped again, etc.

              + * + *

              The output of this method is consistent across JDK versions. + * Note that this is the opposite order to the JDK1.4 display.

              + * + *

              The method is equivalent to printStackTrace for throwables + * that don't have nested causes.

              + * + * @param throwable the throwable to output, may be null + * @param stream the stream to output to, may not be null + * @throws IllegalArgumentException if the stream is null + * @since 2.0 + */ + public static void printRootCauseStackTrace(final Throwable throwable, final PrintStream stream) { + if (throwable == null) { + return; + } + if (stream == null) { + throw new IllegalArgumentException("The PrintStream must not be null"); + } + final String trace[] = getRootCauseStackTrace(throwable); + for (final String element : trace) { + stream.println(element); + } + stream.flush(); + } + + /** + *

              Prints a compact stack trace for the root cause of a throwable.

              + * + *

              The compact stack trace starts with the root cause and prints + * stack frames up to the place where it was caught and wrapped. + * Then it prints the wrapped exception and continues with stack frames + * until the wrapper exception is caught and wrapped again, etc.

              + * + *

              The output of this method is consistent across JDK versions. + * Note that this is the opposite order to the JDK1.4 display.

              + * + *

              The method is equivalent to printStackTrace for throwables + * that don't have nested causes.

              + * + * @param throwable the throwable to output, may be null + * @param writer the writer to output to, may not be null + * @throws IllegalArgumentException if the writer is null + * @since 2.0 + */ + public static void printRootCauseStackTrace(final Throwable throwable, final PrintWriter writer) { + if (throwable == null) { + return; + } + if (writer == null) { + throw new IllegalArgumentException("The PrintWriter must not be null"); + } + final String trace[] = getRootCauseStackTrace(throwable); + for (final String element : trace) { + writer.println(element); + } + writer.flush(); + } + + //----------------------------------------------------------------------- + /** + *

              Creates a compact stack trace for the root cause of the supplied + * Throwable.

              + * + *

              The output of this method is consistent across JDK versions. + * It consists of the root exception followed by each of its wrapping + * exceptions separated by '[wrapped]'. Note that this is the opposite + * order to the JDK1.4 display.

              + * + * @param throwable the throwable to examine, may be null + * @return an array of stack trace frames, never null + * @since 2.0 + */ + public static String[] getRootCauseStackTrace(final Throwable throwable) { + if (throwable == null) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + final Throwable throwables[] = getThrowables(throwable); + final int count = throwables.length; + final List frames = new ArrayList<>(); + List nextTrace = getStackFrameList(throwables[count - 1]); + for (int i = count; --i >= 0;) { + final List trace = nextTrace; + if (i != 0) { + nextTrace = getStackFrameList(throwables[i - 1]); + removeCommonFrames(trace, nextTrace); + } + if (i == count - 1) { + frames.add(throwables[i].toString()); + } else { + frames.add(WRAPPED_MARKER + throwables[i].toString()); + } + for (int j = 0; j < trace.size(); j++) { + frames.add(trace.get(j)); + } + } + return frames.toArray(new String[frames.size()]); + } + + /** + *

              Removes common frames from the cause trace given the two stack traces.

              + * + * @param causeFrames stack trace of a cause throwable + * @param wrapperFrames stack trace of a wrapper throwable + * @throws IllegalArgumentException if either argument is null + * @since 2.0 + */ + public static void removeCommonFrames(final List causeFrames, final List wrapperFrames) { + if (causeFrames == null || wrapperFrames == null) { + throw new IllegalArgumentException("The List must not be null"); + } + int causeFrameIndex = causeFrames.size() - 1; + int wrapperFrameIndex = wrapperFrames.size() - 1; + while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) { + // Remove the frame from the cause trace if it is the same + // as in the wrapper trace + final String causeFrame = causeFrames.get(causeFrameIndex); + final String wrapperFrame = wrapperFrames.get(wrapperFrameIndex); + if (causeFrame.equals(wrapperFrame)) { + causeFrames.remove(causeFrameIndex); + } + causeFrameIndex--; + wrapperFrameIndex--; + } + } + + //----------------------------------------------------------------------- + /** + *

              Gets the stack trace from a Throwable as a String.

              + * + *

              The result of this method vary by JDK version as this method + * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}. + * On JDK1.3 and earlier, the cause exception will not be shown + * unless the specified throwable alters printStackTrace.

              + * + * @param throwable the Throwable to be examined + * @return the stack trace as generated by the exception's + * printStackTrace(PrintWriter) method + */ + public static String getStackTrace(final Throwable throwable) { + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw, true); + throwable.printStackTrace(pw); + return sw.getBuffer().toString(); + } + + /** + *

              Captures the stack trace associated with the specified + * Throwable object, decomposing it into a list of + * stack frames.

              + * + *

              The result of this method vary by JDK version as this method + * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}. + * On JDK1.3 and earlier, the cause exception will not be shown + * unless the specified throwable alters printStackTrace.

              + * + * @param throwable the Throwable to examine, may be null + * @return an array of strings describing each stack frame, never null + */ + public static String[] getStackFrames(final Throwable throwable) { + if (throwable == null) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + return getStackFrames(getStackTrace(throwable)); + } + + //----------------------------------------------------------------------- + /** + *

              Returns an array where each element is a line from the argument.

              + * + *

              The end of line is determined by the value of {@link SystemUtils#LINE_SEPARATOR}.

              + * + * @param stackTrace a stack trace String + * @return an array where each element is a line from the argument + */ + static String[] getStackFrames(final String stackTrace) { + final String linebreak = System.lineSeparator(); + final StringTokenizer frames = new StringTokenizer(stackTrace, linebreak); + final List list = new ArrayList<>(); + while (frames.hasMoreTokens()) { + list.add(frames.nextToken()); + } + return list.toArray(new String[list.size()]); + } + + /** + *

              Produces a List of stack frames - the message + * is not included. Only the trace of the specified exception is + * returned, any caused by trace is stripped.

              + * + *

              This works in most cases - it will only fail if the exception + * message contains a line that starts with: + * "   at".

              + * + * @param t is any throwable + * @return List of stack frames + */ + static List getStackFrameList(final Throwable t) { + final String stackTrace = getStackTrace(t); + final String linebreak = System.lineSeparator(); + final StringTokenizer frames = new StringTokenizer(stackTrace, linebreak); + final List list = new ArrayList<>(); + boolean traceStarted = false; + while (frames.hasMoreTokens()) { + final String token = frames.nextToken(); + // Determine if the line starts with at + final int at = token.indexOf("at"); + if (at != -1 && token.substring(0, at).trim().isEmpty()) { + traceStarted = true; + list.add(token); + } else if (traceStarted) { + break; + } + } + return list; + } + + //----------------------------------------------------------------------- + /** + * Gets a short message summarising the exception. + *

              + * The message returned is of the form + * {ClassNameWithoutPackage}: {ThrowableMessage} + * + * @param th the throwable to get a message for, null returns empty string + * @return the message, non-null + * @since Commons Lang 2.2 + */ + public static String getMessage(final Throwable th) { + if (th == null) { + return StringUtils.EMPTY; + } + final String clsName = ClassUtils.getShortClassName(th, null); + final String msg = th.getMessage(); + return clsName + ": " + StringUtils.defaultString(msg); + } + + //----------------------------------------------------------------------- + /** + * Gets a short message summarising the root cause exception. + *

              + * The message returned is of the form + * {ClassNameWithoutPackage}: {ThrowableMessage} + * + * @param th the throwable to get a message for, null returns empty string + * @return the message, non-null + * @since Commons Lang 2.2 + */ + public static String getRootCauseMessage(final Throwable th) { + Throwable root = ExceptionUtils.getRootCause(th); + root = root == null ? th : root; + return getMessage(root); + } + + /** + * Throw a checked exception without adding the exception to the throws + * clause of the calling method. This method prevents throws clause + * pollution and reduces the clutter of "Caused by" exceptions in the + * stacktrace. + *

              + * The use of this technique may be controversial, but exceedingly useful to + * library developers. + * + * public int propagateExample { // note that there is no throws clause + * try { + * return invocation(); // throws IOException + * } catch (Exception e) { + * return ExceptionUtils.rethrow(e); // propagates a checked exception + * } + * } + * + *

              + * This is an alternative to the more conservative approach of wrapping the + * checked exception in a RuntimeException: + * + * public int wrapExample { // note that there is no throws clause + * try { + * return invocation(); // throws IOException + * } catch (Error e) { + * throw e; + * } catch (RuntimeException e) { + * throw e; // wraps a checked exception + * } catch (Exception e) { + * throw new UndeclaredThrowableException(e); // wraps a checked exception + * } + * } + * + *

              + * One downside to using this approach is that the java compiler will not + * allow invoking code to specify a checked exception in a catch clause + * unless there is some code path within the try block that has invoked a + * method declared with that checked exception. If the invoking site wishes + * to catch the shaded checked exception, it must either invoke the shaded + * code through a method re-declaring the desired checked exception, or + * catch Exception and use the instanceof operator. Either of these + * techniques are required when interacting with non-java jvm code such as + * Jython, Scala, or Groovy, since these languages do not consider any + * exceptions as checked. + * + * @param throwable + * The throwable to rethrow. + * @param The type of the returned value. + * @return Never actually returned, this generic type matches any type + * which the calling site requires. "Returning" the results of this + * method, as done in the propagateExample above, will satisfy the + * java compiler requirement that all code paths return a value. + * @since 3.5 + * @see #wrapAndThrow(Throwable) + */ + public static R rethrow(final Throwable throwable) { + // claim that the typeErasure invocation throws a RuntimeException + return ExceptionUtils. typeErasure(throwable); + } + + /** + * Claim a Throwable is another Exception type using type erasure. This + * hides a checked exception from the java compiler, allowing a checked + * exception to be thrown without having the exception in the method's throw + * clause. + */ + @SuppressWarnings("unchecked") + private static R typeErasure(final Throwable throwable) throws T { + throw (T) throwable; + } + + /** + * Throw a checked exception without adding the exception to the throws + * clause of the calling method. For checked exceptions, this method throws + * an UndeclaredThrowableException wrapping the checked exception. For + * Errors and RuntimeExceptions, the original exception is rethrown. + *

              + * The downside to using this approach is that invoking code which needs to + * handle specific checked exceptions must sniff up the exception chain to + * determine if the caught exception was caused by the checked exception. + * + * @param throwable + * The throwable to rethrow. + * @param The type of the returned value. + * @return Never actually returned, this generic type matches any type + * which the calling site requires. "Returning" the results of this + * method will satisfy the java compiler requirement that all code + * paths return a value. + * @since 3.5 + * @see #rethrow(Throwable) + * @see #hasCause(Throwable, Class) + */ + public static R wrapAndThrow(final Throwable throwable) { + if (throwable instanceof RuntimeException) { + throw (RuntimeException) throwable; + } + if (throwable instanceof Error) { + throw (Error) throwable; + } + throw new UndeclaredThrowableException(throwable); + } + + /** + * Does the throwable's causal chain have an immediate or wrapped exception + * of the given type? + * + * @param chain + * The root of a Throwable causal chain. + * @param type + * The exception type to test. + * @return true, if chain is an instance of type or is an + * UndeclaredThrowableException wrapping a cause. + * @since 3.5 + * @see #wrapAndThrow(Throwable) + */ + public static boolean hasCause(Throwable chain, + final Class type) { + if (chain instanceof UndeclaredThrowableException) { + chain = chain.getCause(); + } + return type.isInstance(chain); + } +} diff --git a/src/org/apache/commons/lang3/exception/package-info.java b/src/org/apache/commons/lang3/exception/package-info.java new file mode 100644 index 0000000..b2f31a9 --- /dev/null +++ b/src/org/apache/commons/lang3/exception/package-info.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Provides functionality for Exceptions.

              + *

              Contains the concept of an exception with context i.e. such an exception will contain a map with keys and values. + * This provides an easy way to pass valuable state information at exception time in useful form to a calling process.

              + *

              Lastly, {@link org.apache.commons.lang3.exception.ExceptionUtils} also contains Throwable manipulation + * and examination routines.

              + * + * @since 1.0 + */ +package org.apache.commons.lang3.exception; diff --git a/src/org/apache/commons/lang3/math/Fraction.java b/src/org/apache/commons/lang3/math/Fraction.java new file mode 100644 index 0000000..4d5c53f --- /dev/null +++ b/src/org/apache/commons/lang3/math/Fraction.java @@ -0,0 +1,939 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.math; + +import java.math.BigInteger; + +/** + *

              Fraction is a Number implementation that + * stores fractions accurately.

              + * + *

              This class is immutable, and interoperable with most methods that accept + * a Number.

              + * + *

              Note that this class is intended for common use cases, it is int + * based and thus suffers from various overflow issues. For a BigInteger based + * equivalent, please see the Commons Math BigFraction class.

              + * + * @since 2.0 + */ +public final class Fraction extends Number implements Comparable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 65382027393090L; + + /** + * Fraction representation of 0. + */ + public static final Fraction ZERO = new Fraction(0, 1); + /** + * Fraction representation of 1. + */ + public static final Fraction ONE = new Fraction(1, 1); + /** + * Fraction representation of 1/2. + */ + public static final Fraction ONE_HALF = new Fraction(1, 2); + /** + * Fraction representation of 1/3. + */ + public static final Fraction ONE_THIRD = new Fraction(1, 3); + /** + * Fraction representation of 2/3. + */ + public static final Fraction TWO_THIRDS = new Fraction(2, 3); + /** + * Fraction representation of 1/4. + */ + public static final Fraction ONE_QUARTER = new Fraction(1, 4); + /** + * Fraction representation of 2/4. + */ + public static final Fraction TWO_QUARTERS = new Fraction(2, 4); + /** + * Fraction representation of 3/4. + */ + public static final Fraction THREE_QUARTERS = new Fraction(3, 4); + /** + * Fraction representation of 1/5. + */ + public static final Fraction ONE_FIFTH = new Fraction(1, 5); + /** + * Fraction representation of 2/5. + */ + public static final Fraction TWO_FIFTHS = new Fraction(2, 5); + /** + * Fraction representation of 3/5. + */ + public static final Fraction THREE_FIFTHS = new Fraction(3, 5); + /** + * Fraction representation of 4/5. + */ + public static final Fraction FOUR_FIFTHS = new Fraction(4, 5); + + + /** + * The numerator number part of the fraction (the three in three sevenths). + */ + private final int numerator; + /** + * The denominator number part of the fraction (the seven in three sevenths). + */ + private final int denominator; + + /** + * Cached output hashCode (class is immutable). + */ + private transient int hashCode = 0; + /** + * Cached output toString (class is immutable). + */ + private transient String toString = null; + /** + * Cached output toProperString (class is immutable). + */ + private transient String toProperString = null; + + /** + *

              Constructs a Fraction instance with the 2 parts + * of a fraction Y/Z.

              + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + */ + private Fraction(final int numerator, final int denominator) { + super(); + this.numerator = numerator; + this.denominator = denominator; + } + + /** + *

              Creates a Fraction instance with the 2 parts + * of a fraction Y/Z.

              + * + *

              Any negative signs are resolved to be on the numerator.

              + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + * @return a new fraction instance + * @throws ArithmeticException if the denominator is zero + * or the denominator is {@code negative} and the numerator is {@code Integer#MIN_VALUE} + */ + public static Fraction getFraction(int numerator, int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (denominator < 0) { + if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate"); + } + numerator = -numerator; + denominator = -denominator; + } + return new Fraction(numerator, denominator); + } + + /** + *

              Creates a Fraction instance with the 3 parts + * of a fraction X Y/Z.

              + * + *

              The negative sign must be passed in on the whole number part.

              + * + * @param whole the whole number, for example the one in 'one and three sevenths' + * @param numerator the numerator, for example the three in 'one and three sevenths' + * @param denominator the denominator, for example the seven in 'one and three sevenths' + * @return a new fraction instance + * @throws ArithmeticException if the denominator is zero + * @throws ArithmeticException if the denominator is negative + * @throws ArithmeticException if the numerator is negative + * @throws ArithmeticException if the resulting numerator exceeds + * Integer.MAX_VALUE + */ + public static Fraction getFraction(final int whole, final int numerator, final int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (denominator < 0) { + throw new ArithmeticException("The denominator must not be negative"); + } + if (numerator < 0) { + throw new ArithmeticException("The numerator must not be negative"); + } + long numeratorValue; + if (whole < 0) { + numeratorValue = whole * (long) denominator - numerator; + } else { + numeratorValue = whole * (long) denominator + numerator; + } + if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) { + throw new ArithmeticException("Numerator too large to represent as an Integer."); + } + return new Fraction((int) numeratorValue, denominator); + } + + /** + *

              Creates a reduced Fraction instance with the 2 parts + * of a fraction Y/Z.

              + * + *

              For example, if the input parameters represent 2/4, then the created + * fraction will be 1/2.

              + * + *

              Any negative signs are resolved to be on the numerator.

              + * + * @param numerator the numerator, for example the three in 'three sevenths' + * @param denominator the denominator, for example the seven in 'three sevenths' + * @return a new fraction instance, with the numerator and denominator reduced + * @throws ArithmeticException if the denominator is zero + */ + public static Fraction getReducedFraction(int numerator, int denominator) { + if (denominator == 0) { + throw new ArithmeticException("The denominator must not be zero"); + } + if (numerator == 0) { + return ZERO; // normalize zero. + } + // allow 2^k/-2^31 as a valid fraction (where k>0) + if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) { + numerator /= 2; + denominator /= 2; + } + if (denominator < 0) { + if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate"); + } + numerator = -numerator; + denominator = -denominator; + } + // simplify fraction. + final int gcd = greatestCommonDivisor(numerator, denominator); + numerator /= gcd; + denominator /= gcd; + return new Fraction(numerator, denominator); + } + + /** + *

              Creates a Fraction instance from a double value.

              + * + *

              This method uses the + * continued fraction algorithm, computing a maximum of + * 25 convergents and bounding the denominator by 10,000.

              + * + * @param value the double value to convert + * @return a new fraction instance that is close to the value + * @throws ArithmeticException if |value| > Integer.MAX_VALUE + * or value = NaN + * @throws ArithmeticException if the calculated denominator is zero + * @throws ArithmeticException if the the algorithm does not converge + */ + public static Fraction getFraction(double value) { + final int sign = value < 0 ? -1 : 1; + value = Math.abs(value); + if (value > Integer.MAX_VALUE || Double.isNaN(value)) { + throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN"); + } + final int wholeNumber = (int) value; + value -= wholeNumber; + + int numer0 = 0; // the pre-previous + int denom0 = 1; // the pre-previous + int numer1 = 1; // the previous + int denom1 = 0; // the previous + int numer2 = 0; // the current, setup in calculation + int denom2 = 0; // the current, setup in calculation + int a1 = (int) value; + int a2 = 0; + double x1 = 1; + double x2 = 0; + double y1 = value - a1; + double y2 = 0; + double delta1, delta2 = Double.MAX_VALUE; + double fraction; + int i = 1; + // System.out.println("---"); + do { + delta1 = delta2; + a2 = (int) (x1 / y1); + x2 = y1; + y2 = x1 - a2 * y1; + numer2 = a1 * numer1 + numer0; + denom2 = a1 * denom1 + denom0; + fraction = (double) numer2 / (double) denom2; + delta2 = Math.abs(value - fraction); + // System.out.println(numer2 + " " + denom2 + " " + fraction + " " + delta2 + " " + y1); + a1 = a2; + x1 = x2; + y1 = y2; + numer0 = numer1; + denom0 = denom1; + numer1 = numer2; + denom1 = denom2; + i++; + // System.out.println(">>" + delta1 +" "+ delta2+" "+(delta1 > delta2)+" "+i+" "+denom2); + } while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25); + if (i == 25) { + throw new ArithmeticException("Unable to convert double to fraction"); + } + return getReducedFraction((numer0 + wholeNumber * denom0) * sign, denom0); + } + + /** + *

              Creates a Fraction from a String.

              + * + *

              The formats accepted are:

              + * + *
                + *
              1. double String containing a dot
              2. + *
              3. 'X Y/Z'
              4. + *
              5. 'Y/Z'
              6. + *
              7. 'X' (a simple whole number)
              8. + *
              + *

              and a .

              + * + * @param str the string to parse, must not be null + * @return the new Fraction instance + * @throws IllegalArgumentException if the string is null + * @throws NumberFormatException if the number format is invalid + */ + public static Fraction getFraction(String str) { + if (str == null) { + throw new IllegalArgumentException("The string must not be null"); + } + // parse double format + int pos = str.indexOf('.'); + if (pos >= 0) { + return getFraction(Double.parseDouble(str)); + } + + // parse X Y/Z format + pos = str.indexOf(' '); + if (pos > 0) { + final int whole = Integer.parseInt(str.substring(0, pos)); + str = str.substring(pos + 1); + pos = str.indexOf('/'); + if (pos < 0) { + throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z"); + } + final int numer = Integer.parseInt(str.substring(0, pos)); + final int denom = Integer.parseInt(str.substring(pos + 1)); + return getFraction(whole, numer, denom); + } + + // parse Y/Z format + pos = str.indexOf('/'); + if (pos < 0) { + // simple whole number + return getFraction(Integer.parseInt(str), 1); + } + final int numer = Integer.parseInt(str.substring(0, pos)); + final int denom = Integer.parseInt(str.substring(pos + 1)); + return getFraction(numer, denom); + } + + // Accessors + //------------------------------------------------------------------- + + /** + *

              Gets the numerator part of the fraction.

              + * + *

              This method may return a value greater than the denominator, an + * improper fraction, such as the seven in 7/4.

              + * + * @return the numerator fraction part + */ + public int getNumerator() { + return numerator; + } + + /** + *

              Gets the denominator part of the fraction.

              + * + * @return the denominator fraction part + */ + public int getDenominator() { + return denominator; + } + + /** + *

              Gets the proper numerator, always positive.

              + * + *

              An improper fraction 7/4 can be resolved into a proper one, 1 3/4. + * This method returns the 3 from the proper fraction.

              + * + *

              If the fraction is negative such as -7/4, it can be resolved into + * -1 3/4, so this method returns the positive proper numerator, 3.

              + * + * @return the numerator fraction part of a proper fraction, always positive + */ + public int getProperNumerator() { + return Math.abs(numerator % denominator); + } + + /** + *

              Gets the proper whole part of the fraction.

              + * + *

              An improper fraction 7/4 can be resolved into a proper one, 1 3/4. + * This method returns the 1 from the proper fraction.

              + * + *

              If the fraction is negative such as -7/4, it can be resolved into + * -1 3/4, so this method returns the positive whole part -1.

              + * + * @return the whole fraction part of a proper fraction, that includes the sign + */ + public int getProperWhole() { + return numerator / denominator; + } + + // Number methods + //------------------------------------------------------------------- + + /** + *

              Gets the fraction as an int. This returns the whole number + * part of the fraction.

              + * + * @return the whole number fraction part + */ + @Override + public int intValue() { + return numerator / denominator; + } + + /** + *

              Gets the fraction as a long. This returns the whole number + * part of the fraction.

              + * + * @return the whole number fraction part + */ + @Override + public long longValue() { + return (long) numerator / denominator; + } + + /** + *

              Gets the fraction as a float. This calculates the fraction + * as the numerator divided by denominator.

              + * + * @return the fraction as a float + */ + @Override + public float floatValue() { + return (float) numerator / (float) denominator; + } + + /** + *

              Gets the fraction as a double. This calculates the fraction + * as the numerator divided by denominator.

              + * + * @return the fraction as a double + */ + @Override + public double doubleValue() { + return (double) numerator / (double) denominator; + } + + // Calculations + //------------------------------------------------------------------- + + /** + *

              Reduce the fraction to the smallest values for the numerator and + * denominator, returning the result.

              + * + *

              For example, if this fraction represents 2/4, then the result + * will be 1/2.

              + * + * @return a new reduced fraction instance, or this if no simplification possible + */ + public Fraction reduce() { + if (numerator == 0) { + return equals(ZERO) ? this : ZERO; + } + final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator); + if (gcd == 1) { + return this; + } + return Fraction.getFraction(numerator / gcd, denominator / gcd); + } + + /** + *

              Gets a fraction that is the inverse (1/fraction) of this one.

              + * + *

              The returned fraction is not reduced.

              + * + * @return a new fraction instance with the numerator and denominator + * inverted. + * @throws ArithmeticException if the fraction represents zero. + */ + public Fraction invert() { + if (numerator == 0) { + throw new ArithmeticException("Unable to invert zero."); + } + if (numerator==Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: can't negate numerator"); + } + if (numerator<0) { + return new Fraction(-denominator, -numerator); + } + return new Fraction(denominator, numerator); + } + + /** + *

              Gets a fraction that is the negative (-fraction) of this one.

              + * + *

              The returned fraction is not reduced.

              + * + * @return a new fraction instance with the opposite signed numerator + */ + public Fraction negate() { + // the positive range is one smaller than the negative range of an int. + if (numerator==Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: too large to negate"); + } + return new Fraction(-numerator, denominator); + } + + /** + *

              Gets a fraction that is the positive equivalent of this one.

              + *

              More precisely: (fraction >= 0 ? this : -fraction)

              + * + *

              The returned fraction is not reduced.

              + * + * @return this if it is positive, or a new positive fraction + * instance with the opposite signed numerator + */ + public Fraction abs() { + if (numerator >= 0) { + return this; + } + return negate(); + } + + /** + *

              Gets a fraction that is raised to the passed in power.

              + * + *

              The returned fraction is in reduced form.

              + * + * @param power the power to raise the fraction to + * @return this if the power is one, ONE if the power + * is zero (even if the fraction equals ZERO) or a new fraction instance + * raised to the appropriate power + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * Integer.MAX_VALUE + */ + public Fraction pow(final int power) { + if (power == 1) { + return this; + } else if (power == 0) { + return ONE; + } else if (power < 0) { + if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated. + return this.invert().pow(2).pow(-(power / 2)); + } + return this.invert().pow(-power); + } else { + final Fraction f = this.multiplyBy(this); + if (power % 2 == 0) { // if even... + return f.pow(power / 2); + } + return f.pow(power / 2).multiplyBy(this); + } + } + + /** + *

              Gets the greatest common divisor of the absolute value of + * two numbers, using the "binary gcd" method which avoids + * division and modulo operations. See Knuth 4.5.2 algorithm B. + * This algorithm is due to Josef Stein (1961).

              + * + * @param u a non-zero number + * @param v a non-zero number + * @return the greatest common divisor, never zero + */ + private static int greatestCommonDivisor(int u, int v) { + // From Commons Math: + if (u == 0 || v == 0) { + if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) { + throw new ArithmeticException("overflow: gcd is 2^31"); + } + return Math.abs(u) + Math.abs(v); + } + // if either operand is abs 1, return 1: + if (Math.abs(u) == 1 || Math.abs(v) == 1) { + return 1; + } + // keep u and v negative, as negative integers range down to + // -2^31, while positive numbers can only be as large as 2^31-1 + // (i.e. we can't necessarily negate a negative number without + // overflow) + if (u > 0) { + u = -u; + } // make u negative + if (v > 0) { + v = -v; + } // make v negative + // B1. [Find power of 2] + int k = 0; + while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even... + u /= 2; + v /= 2; + k++; // cast out twos. + } + if (k == 31) { + throw new ArithmeticException("overflow: gcd is 2^31"); + } + // B2. Initialize: u and v have been divided by 2^k and at least + // one is odd. + int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */; + // t negative: u was odd, v may be even (t replaces v) + // t positive: u was even, v is odd (t replaces u) + do { + /* assert u<0 && v<0; */ + // B4/B3: cast out twos from t. + while ((t & 1) == 0) { // while t is even.. + t /= 2; // cast out twos + } + // B5 [reset max(u,v)] + if (t > 0) { + u = -t; + } else { + v = t; + } + // B6/B3. at this point both u and v should be odd. + t = (v - u) / 2; + // |u| larger: t positive (replace u) + // |v| larger: t negative (replace v) + } while (t != 0); + return -u * (1 << k); // gcd is u*2^k + } + + // Arithmetic + //------------------------------------------------------------------- + + /** + * Multiply two integers, checking for overflow. + * + * @param x a factor + * @param y a factor + * @return the product x*y + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int mulAndCheck(final int x, final int y) { + final long m = (long) x * (long) y; + if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: mul"); + } + return (int) m; + } + + /** + * Multiply two non-negative integers, checking for overflow. + * + * @param x a non-negative factor + * @param y a non-negative factor + * @return the product x*y + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int mulPosAndCheck(final int x, final int y) { + /* assert x>=0 && y>=0; */ + final long m = (long) x * (long) y; + if (m > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: mulPos"); + } + return (int) m; + } + + /** + * Add two integers, checking for overflow. + * + * @param x an addend + * @param y an addend + * @return the sum x+y + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int addAndCheck(final int x, final int y) { + final long s = (long) x + (long) y; + if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: add"); + } + return (int) s; + } + + /** + * Subtract two integers, checking for overflow. + * + * @param x the minuend + * @param y the subtrahend + * @return the difference x-y + * @throws ArithmeticException if the result can not be represented as + * an int + */ + private static int subAndCheck(final int x, final int y) { + final long s = (long) x - (long) y; + if (s < Integer.MIN_VALUE || s > Integer.MAX_VALUE) { + throw new ArithmeticException("overflow: add"); + } + return (int) s; + } + + /** + *

              Adds the value of this fraction to another, returning the result in reduced form. + * The algorithm follows Knuth, 4.5.1.

              + * + * @param fraction the fraction to add, must not be null + * @return a Fraction instance with the resulting values + * @throws IllegalArgumentException if the fraction is null + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * Integer.MAX_VALUE + */ + public Fraction add(final Fraction fraction) { + return addSub(fraction, true /* add */); + } + + /** + *

              Subtracts the value of another fraction from the value of this one, + * returning the result in reduced form.

              + * + * @param fraction the fraction to subtract, must not be null + * @return a Fraction instance with the resulting values + * @throws IllegalArgumentException if the fraction is null + * @throws ArithmeticException if the resulting numerator or denominator + * cannot be represented in an int. + */ + public Fraction subtract(final Fraction fraction) { + return addSub(fraction, false /* subtract */); + } + + /** + * Implement add and subtract using algorithm described in Knuth 4.5.1. + * + * @param fraction the fraction to subtract, must not be null + * @param isAdd true to add, false to subtract + * @return a Fraction instance with the resulting values + * @throws IllegalArgumentException if the fraction is null + * @throws ArithmeticException if the resulting numerator or denominator + * cannot be represented in an int. + */ + private Fraction addSub(final Fraction fraction, final boolean isAdd) { + if (fraction == null) { + throw new IllegalArgumentException("The fraction must not be null"); + } + // zero is identity for addition. + if (numerator == 0) { + return isAdd ? fraction : fraction.negate(); + } + if (fraction.numerator == 0) { + return this; + } + // if denominators are randomly distributed, d1 will be 1 about 61% + // of the time. + final int d1 = greatestCommonDivisor(denominator, fraction.denominator); + if (d1 == 1) { + // result is ( (u*v' +/- u'v) / u'v') + final int uvp = mulAndCheck(numerator, fraction.denominator); + final int upv = mulAndCheck(fraction.numerator, denominator); + return new Fraction(isAdd ? addAndCheck(uvp, upv) : subAndCheck(uvp, upv), mulPosAndCheck(denominator, + fraction.denominator)); + } + // the quantity 't' requires 65 bits of precision; see knuth 4.5.1 + // exercise 7. we're going to use a BigInteger. + // t = u(v'/d1) +/- v(u'/d1) + final BigInteger uvp = BigInteger.valueOf(numerator).multiply(BigInteger.valueOf(fraction.denominator / d1)); + final BigInteger upv = BigInteger.valueOf(fraction.numerator).multiply(BigInteger.valueOf(denominator / d1)); + final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv); + // but d2 doesn't need extra precision because + // d2 = gcd(t,d1) = gcd(t mod d1, d1) + final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue(); + final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1); + + // result is (t/d2) / (u'/d1)(v'/d2) + final BigInteger w = t.divide(BigInteger.valueOf(d2)); + if (w.bitLength() > 31) { + throw new ArithmeticException("overflow: numerator too large after multiply"); + } + return new Fraction(w.intValue(), mulPosAndCheck(denominator / d1, fraction.denominator / d2)); + } + + /** + *

              Multiplies the value of this fraction by another, returning the + * result in reduced form.

              + * + * @param fraction the fraction to multiply by, must not be null + * @return a Fraction instance with the resulting values + * @throws IllegalArgumentException if the fraction is null + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * Integer.MAX_VALUE + */ + public Fraction multiplyBy(final Fraction fraction) { + if (fraction == null) { + throw new IllegalArgumentException("The fraction must not be null"); + } + if (numerator == 0 || fraction.numerator == 0) { + return ZERO; + } + // knuth 4.5.1 + // make sure we don't overflow unless the result *must* overflow. + final int d1 = greatestCommonDivisor(numerator, fraction.denominator); + final int d2 = greatestCommonDivisor(fraction.numerator, denominator); + return getReducedFraction(mulAndCheck(numerator / d1, fraction.numerator / d2), + mulPosAndCheck(denominator / d2, fraction.denominator / d1)); + } + + /** + *

              Divide the value of this fraction by another.

              + * + * @param fraction the fraction to divide by, must not be null + * @return a Fraction instance with the resulting values + * @throws IllegalArgumentException if the fraction is null + * @throws ArithmeticException if the fraction to divide by is zero + * @throws ArithmeticException if the resulting numerator or denominator exceeds + * Integer.MAX_VALUE + */ + public Fraction divideBy(final Fraction fraction) { + if (fraction == null) { + throw new IllegalArgumentException("The fraction must not be null"); + } + if (fraction.numerator == 0) { + throw new ArithmeticException("The fraction to divide by must not be zero"); + } + return multiplyBy(fraction.invert()); + } + + // Basics + //------------------------------------------------------------------- + + /** + *

              Compares this fraction to another object to test if they are equal.

              . + * + *

              To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.

              + * + * @param obj the reference object with which to compare + * @return true if this object is equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Fraction == false) { + return false; + } + final Fraction other = (Fraction) obj; + return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator(); + } + + /** + *

              Gets a hashCode for the fraction.

              + * + * @return a hash code value for this object + */ + @Override + public int hashCode() { + if (hashCode == 0) { + // hash code update should be atomic. + hashCode = 37 * (37 * 17 + getNumerator()) + getDenominator(); + } + return hashCode; + } + + /** + *

              Compares this object to another based on size.

              + * + *

              Note: this class has a natural ordering that is inconsistent + * with equals, because, for example, equals treats 1/2 and 2/4 as + * different, whereas compareTo treats them as equal. + * + * @param other the object to compare to + * @return -1 if this is less, 0 if equal, +1 if greater + * @throws ClassCastException if the object is not a Fraction + * @throws NullPointerException if the object is null + */ + @Override + public int compareTo(final Fraction other) { + if (this == other) { + return 0; + } + if (numerator == other.numerator && denominator == other.denominator) { + return 0; + } + + // otherwise see which is less + final long first = (long) numerator * (long) other.denominator; + final long second = (long) other.numerator * (long) denominator; + if (first == second) { + return 0; + } else if (first < second) { + return -1; + } else { + return 1; + } + } + + /** + *

              Gets the fraction as a String.

              + * + *

              The format used is 'numerator/denominator' always. + * + * @return a String form of the fraction + */ + @Override + public String toString() { + if (toString == null) { + toString = getNumerator() + "/" + getDenominator(); + } + return toString; + } + + /** + *

              Gets the fraction as a proper String in the format X Y/Z.

              + * + *

              The format used in 'wholeNumber numerator/denominator'. + * If the whole number is zero it will be omitted. If the numerator is zero, + * only the whole number is returned.

              + * + * @return a String form of the fraction + */ + public String toProperString() { + if (toProperString == null) { + if (numerator == 0) { + toProperString = "0"; + } else if (numerator == denominator) { + toProperString = "1"; + } else if (numerator == -1 * denominator) { + toProperString = "-1"; + } else if ((numerator > 0 ? -numerator : numerator) < -denominator) { + // note that we do the magnitude comparison test above with + // NEGATIVE (not positive) numbers, since negative numbers + // have a larger range. otherwise numerator==Integer.MIN_VALUE + // is handled incorrectly. + final int properNumerator = getProperNumerator(); + if (properNumerator == 0) { + toProperString = Integer.toString(getProperWhole()); + } else { + toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator(); + } + } else { + toProperString = getNumerator() + "/" + getDenominator(); + } + } + return toProperString; + } +} diff --git a/src/org/apache/commons/lang3/math/IEEE754rUtils.java b/src/org/apache/commons/lang3/math/IEEE754rUtils.java new file mode 100644 index 0000000..6d34e62 --- /dev/null +++ b/src/org/apache/commons/lang3/math/IEEE754rUtils.java @@ -0,0 +1,267 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.math; + +import org.apache.commons.lang3.Validate; + +/** + *

              Provides IEEE-754r variants of NumberUtils methods.

              + * + *

              See: http://en.wikipedia.org/wiki/IEEE_754r

              + * + * @since 2.4 + */ +public class IEEE754rUtils { + + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from min(double[]) to min(double...) + */ + public static double min(final double... array) { + // Validates input + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + Validate.isTrue(array.length != 0, "Array cannot be empty."); + + + // Finds and returns min + double min = array[0]; + for (int i = 1; i < array.length; i++) { + min = min(array[i], min); + } + + return min; + } + + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from min(float[]) to min(float...) + */ + public static float min(final float... array) { + // Validates input + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + Validate.isTrue(array.length != 0, "Array cannot be empty."); + + // Finds and returns min + float min = array[0]; + for (int i = 1; i < array.length; i++) { + min = min(array[i], min); + } + + return min; + } + + /** + *

              Gets the minimum of three double values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + */ + public static double min(final double a, final double b, final double c) { + return min(min(a, b), c); + } + + /** + *

              Gets the minimum of two double values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @return the smallest of the values + */ + public static double min(final double a, final double b) { + if(Double.isNaN(a)) { + return b; + } else + if(Double.isNaN(b)) { + return a; + } else { + return Math.min(a, b); + } + } + + /** + *

              Gets the minimum of three float values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + */ + public static float min(final float a, final float b, final float c) { + return min(min(a, b), c); + } + + /** + *

              Gets the minimum of two float values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @return the smallest of the values + */ + public static float min(final float a, final float b) { + if(Float.isNaN(a)) { + return b; + } else + if(Float.isNaN(b)) { + return a; + } else { + return Math.min(a, b); + } + } + + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from max(double[]) to max(double...) + */ + public static double max(final double... array) { + // Validates input + if (array== null) { + throw new IllegalArgumentException("The Array must not be null"); + } + Validate.isTrue(array.length != 0, "Array cannot be empty."); + + // Finds and returns max + double max = array[0]; + for (int j = 1; j < array.length; j++) { + max = max(array[j], max); + } + + return max; + } + + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from max(float[]) to max(float...) + */ + public static float max(final float... array) { + // Validates input + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + Validate.isTrue(array.length != 0, "Array cannot be empty."); + + // Finds and returns max + float max = array[0]; + for (int j = 1; j < array.length; j++) { + max = max(array[j], max); + } + + return max; + } + + /** + *

              Gets the maximum of three double values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + */ + public static double max(final double a, final double b, final double c) { + return max(max(a, b), c); + } + + /** + *

              Gets the maximum of two double values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @return the largest of the values + */ + public static double max(final double a, final double b) { + if(Double.isNaN(a)) { + return b; + } else + if(Double.isNaN(b)) { + return a; + } else { + return Math.max(a, b); + } + } + + /** + *

              Gets the maximum of three float values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + */ + public static float max(final float a, final float b, final float c) { + return max(max(a, b), c); + } + + /** + *

              Gets the maximum of two float values.

              + * + *

              NaN is only returned if all numbers are NaN as per IEEE-754r.

              + * + * @param a value 1 + * @param b value 2 + * @return the largest of the values + */ + public static float max(final float a, final float b) { + if(Float.isNaN(a)) { + return b; + } else + if(Float.isNaN(b)) { + return a; + } else { + return Math.max(a, b); + } + } + +} diff --git a/src/org/apache/commons/lang3/math/NumberUtils.java b/src/org/apache/commons/lang3/math/NumberUtils.java new file mode 100644 index 0000000..3dcafac --- /dev/null +++ b/src/org/apache/commons/lang3/math/NumberUtils.java @@ -0,0 +1,1633 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.math; + +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; +import org.apache.commons.lang3.Validate; + +/** + *

              Provides extra functionality for Java Number classes.

              + * + * @since 2.0 + */ +public class NumberUtils { + + /** Reusable Long constant for zero. */ + public static final Long LONG_ZERO = Long.valueOf(0L); + /** Reusable Long constant for one. */ + public static final Long LONG_ONE = Long.valueOf(1L); + /** Reusable Long constant for minus one. */ + public static final Long LONG_MINUS_ONE = Long.valueOf(-1L); + /** Reusable Integer constant for zero. */ + public static final Integer INTEGER_ZERO = Integer.valueOf(0); + /** Reusable Integer constant for one. */ + public static final Integer INTEGER_ONE = Integer.valueOf(1); + /** Reusable Integer constant for minus one. */ + public static final Integer INTEGER_MINUS_ONE = Integer.valueOf(-1); + /** Reusable Short constant for zero. */ + public static final Short SHORT_ZERO = Short.valueOf((short) 0); + /** Reusable Short constant for one. */ + public static final Short SHORT_ONE = Short.valueOf((short) 1); + /** Reusable Short constant for minus one. */ + public static final Short SHORT_MINUS_ONE = Short.valueOf((short) -1); + /** Reusable Byte constant for zero. */ + public static final Byte BYTE_ZERO = Byte.valueOf((byte) 0); + /** Reusable Byte constant for one. */ + public static final Byte BYTE_ONE = Byte.valueOf((byte) 1); + /** Reusable Byte constant for minus one. */ + public static final Byte BYTE_MINUS_ONE = Byte.valueOf((byte) -1); + /** Reusable Double constant for zero. */ + public static final Double DOUBLE_ZERO = Double.valueOf(0.0d); + /** Reusable Double constant for one. */ + public static final Double DOUBLE_ONE = Double.valueOf(1.0d); + /** Reusable Double constant for minus one. */ + public static final Double DOUBLE_MINUS_ONE = Double.valueOf(-1.0d); + /** Reusable Float constant for zero. */ + public static final Float FLOAT_ZERO = Float.valueOf(0.0f); + /** Reusable Float constant for one. */ + public static final Float FLOAT_ONE = Float.valueOf(1.0f); + /** Reusable Float constant for minus one. */ + public static final Float FLOAT_MINUS_ONE = Float.valueOf(-1.0f); + + /** + *

              NumberUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as NumberUtils.toInt("6");.

              + * + *

              This constructor is public to permit tools that require a JavaBean instance + * to operate.

              + */ + public NumberUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

              Convert a String to an int, returning + * zero if the conversion fails.

              + * + *

              If the string is null, zero is returned.

              + * + *
              +     *   NumberUtils.toInt(null) = 0
              +     *   NumberUtils.toInt("")   = 0
              +     *   NumberUtils.toInt("1")  = 1
              +     * 
              + * + * @param str the string to convert, may be null + * @return the int represented by the string, or zero if + * conversion fails + * @since 2.1 + */ + public static int toInt(final String str) { + return toInt(str, 0); + } + + /** + *

              Convert a String to an int, returning a + * default value if the conversion fails.

              + * + *

              If the string is null, the default value is returned.

              + * + *
              +     *   NumberUtils.toInt(null, 1) = 1
              +     *   NumberUtils.toInt("", 1)   = 1
              +     *   NumberUtils.toInt("1", 0)  = 1
              +     * 
              + * + * @param str the string to convert, may be null + * @param defaultValue the default value + * @return the int represented by the string, or the default if conversion fails + * @since 2.1 + */ + public static int toInt(final String str, final int defaultValue) { + if(str == null) { + return defaultValue; + } + try { + return Integer.parseInt(str); + } catch (final NumberFormatException nfe) { + return defaultValue; + } + } + + /** + *

              Convert a String to a long, returning + * zero if the conversion fails.

              + * + *

              If the string is null, zero is returned.

              + * + *
              +     *   NumberUtils.toLong(null) = 0L
              +     *   NumberUtils.toLong("")   = 0L
              +     *   NumberUtils.toLong("1")  = 1L
              +     * 
              + * + * @param str the string to convert, may be null + * @return the long represented by the string, or 0 if + * conversion fails + * @since 2.1 + */ + public static long toLong(final String str) { + return toLong(str, 0L); + } + + /** + *

              Convert a String to a long, returning a + * default value if the conversion fails.

              + * + *

              If the string is null, the default value is returned.

              + * + *
              +     *   NumberUtils.toLong(null, 1L) = 1L
              +     *   NumberUtils.toLong("", 1L)   = 1L
              +     *   NumberUtils.toLong("1", 0L)  = 1L
              +     * 
              + * + * @param str the string to convert, may be null + * @param defaultValue the default value + * @return the long represented by the string, or the default if conversion fails + * @since 2.1 + */ + public static long toLong(final String str, final long defaultValue) { + if (str == null) { + return defaultValue; + } + try { + return Long.parseLong(str); + } catch (final NumberFormatException nfe) { + return defaultValue; + } + } + + /** + *

              Convert a String to a float, returning + * 0.0f if the conversion fails.

              + * + *

              If the string str is null, + * 0.0f is returned.

              + * + *
              +     *   NumberUtils.toFloat(null)   = 0.0f
              +     *   NumberUtils.toFloat("")     = 0.0f
              +     *   NumberUtils.toFloat("1.5")  = 1.5f
              +     * 
              + * + * @param str the string to convert, may be null + * @return the float represented by the string, or 0.0f + * if conversion fails + * @since 2.1 + */ + public static float toFloat(final String str) { + return toFloat(str, 0.0f); + } + + /** + *

              Convert a String to a float, returning a + * default value if the conversion fails.

              + * + *

              If the string str is null, the default + * value is returned.

              + * + *
              +     *   NumberUtils.toFloat(null, 1.1f)   = 1.0f
              +     *   NumberUtils.toFloat("", 1.1f)     = 1.1f
              +     *   NumberUtils.toFloat("1.5", 0.0f)  = 1.5f
              +     * 
              + * + * @param str the string to convert, may be null + * @param defaultValue the default value + * @return the float represented by the string, or defaultValue + * if conversion fails + * @since 2.1 + */ + public static float toFloat(final String str, final float defaultValue) { + if (str == null) { + return defaultValue; + } + try { + return Float.parseFloat(str); + } catch (final NumberFormatException nfe) { + return defaultValue; + } + } + + /** + *

              Convert a String to a double, returning + * 0.0d if the conversion fails.

              + * + *

              If the string str is null, + * 0.0d is returned.

              + * + *
              +     *   NumberUtils.toDouble(null)   = 0.0d
              +     *   NumberUtils.toDouble("")     = 0.0d
              +     *   NumberUtils.toDouble("1.5")  = 1.5d
              +     * 
              + * + * @param str the string to convert, may be null + * @return the double represented by the string, or 0.0d + * if conversion fails + * @since 2.1 + */ + public static double toDouble(final String str) { + return toDouble(str, 0.0d); + } + + /** + *

              Convert a String to a double, returning a + * default value if the conversion fails.

              + * + *

              If the string str is null, the default + * value is returned.

              + * + *
              +     *   NumberUtils.toDouble(null, 1.1d)   = 1.1d
              +     *   NumberUtils.toDouble("", 1.1d)     = 1.1d
              +     *   NumberUtils.toDouble("1.5", 0.0d)  = 1.5d
              +     * 
              + * + * @param str the string to convert, may be null + * @param defaultValue the default value + * @return the double represented by the string, or defaultValue + * if conversion fails + * @since 2.1 + */ + public static double toDouble(final String str, final double defaultValue) { + if (str == null) { + return defaultValue; + } + try { + return Double.parseDouble(str); + } catch (final NumberFormatException nfe) { + return defaultValue; + } + } + + //----------------------------------------------------------------------- + /** + *

              Convert a String to a byte, returning + * zero if the conversion fails.

              + * + *

              If the string is null, zero is returned.

              + * + *
              +     *   NumberUtils.toByte(null) = 0
              +     *   NumberUtils.toByte("")   = 0
              +     *   NumberUtils.toByte("1")  = 1
              +     * 
              + * + * @param str the string to convert, may be null + * @return the byte represented by the string, or zero if + * conversion fails + * @since 2.5 + */ + public static byte toByte(final String str) { + return toByte(str, (byte) 0); + } + + /** + *

              Convert a String to a byte, returning a + * default value if the conversion fails.

              + * + *

              If the string is null, the default value is returned.

              + * + *
              +     *   NumberUtils.toByte(null, 1) = 1
              +     *   NumberUtils.toByte("", 1)   = 1
              +     *   NumberUtils.toByte("1", 0)  = 1
              +     * 
              + * + * @param str the string to convert, may be null + * @param defaultValue the default value + * @return the byte represented by the string, or the default if conversion fails + * @since 2.5 + */ + public static byte toByte(final String str, final byte defaultValue) { + if(str == null) { + return defaultValue; + } + try { + return Byte.parseByte(str); + } catch (final NumberFormatException nfe) { + return defaultValue; + } + } + + /** + *

              Convert a String to a short, returning + * zero if the conversion fails.

              + * + *

              If the string is null, zero is returned.

              + * + *
              +     *   NumberUtils.toShort(null) = 0
              +     *   NumberUtils.toShort("")   = 0
              +     *   NumberUtils.toShort("1")  = 1
              +     * 
              + * + * @param str the string to convert, may be null + * @return the short represented by the string, or zero if + * conversion fails + * @since 2.5 + */ + public static short toShort(final String str) { + return toShort(str, (short) 0); + } + + /** + *

              Convert a String to an short, returning a + * default value if the conversion fails.

              + * + *

              If the string is null, the default value is returned.

              + * + *
              +     *   NumberUtils.toShort(null, 1) = 1
              +     *   NumberUtils.toShort("", 1)   = 1
              +     *   NumberUtils.toShort("1", 0)  = 1
              +     * 
              + * + * @param str the string to convert, may be null + * @param defaultValue the default value + * @return the short represented by the string, or the default if conversion fails + * @since 2.5 + */ + public static short toShort(final String str, final short defaultValue) { + if(str == null) { + return defaultValue; + } + try { + return Short.parseShort(str); + } catch (final NumberFormatException nfe) { + return defaultValue; + } + } + + //----------------------------------------------------------------------- + // must handle Long, Float, Integer, Float, Short, + // BigDecimal, BigInteger and Byte + // useful methods: + // Byte.decode(String) + // Byte.valueOf(String,int radix) + // Byte.valueOf(String) + // Double.valueOf(String) + // Float.valueOf(String) + // Float.valueOf(String) + // Integer.valueOf(String,int radix) + // Integer.valueOf(String) + // Integer.decode(String) + // Integer.getInteger(String) + // Integer.getInteger(String,int val) + // Integer.getInteger(String,Integer val) + // Integer.valueOf(String) + // Double.valueOf(String) + // new Byte(String) + // Long.valueOf(String) + // Long.getLong(String) + // Long.getLong(String,int) + // Long.getLong(String,Integer) + // Long.valueOf(String,int) + // Long.valueOf(String) + // Short.valueOf(String) + // Short.decode(String) + // Short.valueOf(String,int) + // Short.valueOf(String) + // new BigDecimal(String) + // new BigInteger(String) + // new BigInteger(String,int radix) + // Possible inputs: + // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd + // plus minus everything. Prolly more. A lot are not separable. + + /** + *

              Turns a string value into a java.lang.Number.

              + * + *

              If the string starts with {@code 0x} or {@code -0x} (lower or upper case) or {@code #} or {@code -#}, it + * will be interpreted as a hexadecimal Integer - or Long, if the number of digits after the + * prefix is more than 8 - or BigInteger if there are more than 16 digits. + *

              + *

              Then, the value is examined for a type qualifier on the end, i.e. one of + * 'f','F','d','D','l','L'. If it is found, it starts + * trying to create successively larger types from the type specified + * until one is found that can represent the value.

              + * + *

              If a type specifier is not found, it will check for a decimal point + * and then try successively larger types from Integer to + * BigInteger and from Float to + * BigDecimal.

              + * + *

              + * Integral values with a leading {@code 0} will be interpreted as octal; the returned number will + * be Integer, Long or BigDecimal as appropriate. + *

              + * + *

              Returns null if the string is null.

              + * + *

              This method does not trim the input string, i.e., strings with leading + * or trailing spaces will generate NumberFormatExceptions.

              + * + * @param str String containing a number, may be null + * @return Number created from the string (or null if the input is null) + * @throws NumberFormatException if the value cannot be converted + */ + public static Number createNumber(final String str) throws NumberFormatException { + if (str == null) { + return null; + } + if (StringUtils.isBlank(str)) { + throw new NumberFormatException("A blank string is not a valid number"); + } + // Need to deal with all possible hex prefixes here + final String[] hex_prefixes = {"0x", "0X", "-0x", "-0X", "#", "-#"}; + int pfxLen = 0; + for(final String pfx : hex_prefixes) { + if (str.startsWith(pfx)) { + pfxLen += pfx.length(); + break; + } + } + if (pfxLen > 0) { // we have a hex number + char firstSigDigit = 0; // strip leading zeroes + for(int i = pfxLen; i < str.length(); i++) { + firstSigDigit = str.charAt(i); + if (firstSigDigit == '0') { // count leading zeroes + pfxLen++; + } else { + break; + } + } + final int hexDigits = str.length() - pfxLen; + if (hexDigits > 16 || hexDigits == 16 && firstSigDigit > '7') { // too many for Long + return createBigInteger(str); + } + if (hexDigits > 8 || hexDigits == 8 && firstSigDigit > '7') { // too many for an int + return createLong(str); + } + return createInteger(str); + } + final char lastChar = str.charAt(str.length() - 1); + String mant; + String dec; + String exp; + final int decPos = str.indexOf('.'); + final int expPos = str.indexOf('e') + str.indexOf('E') + 1; // assumes both not present + // if both e and E are present, this is caught by the checks on expPos (which prevent IOOBE) + // and the parsing which will detect if e or E appear in a number due to using the wrong offset + + if (decPos > -1) { // there is a decimal point + if (expPos > -1) { // there is an exponent + if (expPos < decPos || expPos > str.length()) { // prevents double exponent causing IOOBE + throw new NumberFormatException(str + " is not a valid number."); + } + dec = str.substring(decPos + 1, expPos); + } else { + dec = str.substring(decPos + 1); + } + mant = getMantissa(str, decPos); + } else { + if (expPos > -1) { + if (expPos > str.length()) { // prevents double exponent causing IOOBE + throw new NumberFormatException(str + " is not a valid number."); + } + mant = getMantissa(str, expPos); + } else { + mant = getMantissa(str); + } + dec = null; + } + if (!Character.isDigit(lastChar) && lastChar != '.') { + if (expPos > -1 && expPos < str.length() - 1) { + exp = str.substring(expPos + 1, str.length() - 1); + } else { + exp = null; + } + //Requesting a specific type.. + final String numeric = str.substring(0, str.length() - 1); + final boolean allZeros = isAllZeros(mant) && isAllZeros(exp); + switch (lastChar) { + case 'l' : + case 'L' : + if (dec == null + && exp == null + && (numeric.charAt(0) == '-' && isDigits(numeric.substring(1)) || isDigits(numeric))) { + try { + return createLong(numeric); + } catch (final NumberFormatException nfe) { // NOPMD + // Too big for a long + } + return createBigInteger(numeric); + + } + throw new NumberFormatException(str + " is not a valid number."); + case 'f' : + case 'F' : + try { + final Float f = NumberUtils.createFloat(str); + if (!(f.isInfinite() || f.floatValue() == 0.0F && !allZeros)) { + //If it's too big for a float or the float value = 0 and the string + //has non-zeros in it, then float does not have the precision we want + return f; + } + + } catch (final NumberFormatException nfe) { // NOPMD + // ignore the bad number + } + //$FALL-THROUGH$ + case 'd' : + case 'D' : + try { + final Double d = NumberUtils.createDouble(str); + if (!(d.isInfinite() || d.floatValue() == 0.0D && !allZeros)) { + return d; + } + } catch (final NumberFormatException nfe) { // NOPMD + // ignore the bad number + } + try { + return createBigDecimal(numeric); + } catch (final NumberFormatException e) { // NOPMD + // ignore the bad number + } + //$FALL-THROUGH$ + default : + throw new NumberFormatException(str + " is not a valid number."); + + } + } + //User doesn't have a preference on the return type, so let's start + //small and go from there... + if (expPos > -1 && expPos < str.length() - 1) { + exp = str.substring(expPos + 1, str.length()); + } else { + exp = null; + } + if (dec == null && exp == null) { // no decimal point and no exponent + //Must be an Integer, Long, Biginteger + try { + return createInteger(str); + } catch (final NumberFormatException nfe) { // NOPMD + // ignore the bad number + } + try { + return createLong(str); + } catch (final NumberFormatException nfe) { // NOPMD + // ignore the bad number + } + return createBigInteger(str); + } + + //Must be a Float, Double, BigDecimal + final boolean allZeros = isAllZeros(mant) && isAllZeros(exp); + try { + final Float f = createFloat(str); + final Double d = createDouble(str); + if (!f.isInfinite() + && !(f.floatValue() == 0.0F && !allZeros) + && f.toString().equals(d.toString())) { + return f; + } + if (!d.isInfinite() && !(d.doubleValue() == 0.0D && !allZeros)) { + final BigDecimal b = createBigDecimal(str); + if (b.compareTo(BigDecimal.valueOf(d.doubleValue())) == 0) { + return d; + } + return b; + } + } catch (final NumberFormatException nfe) { // NOPMD + // ignore the bad number + } + return createBigDecimal(str); + } + + /** + *

              Utility method for {@link #createNumber(java.lang.String)}.

              + * + *

              Returns mantissa of the given number.

              + * + * @param str the string representation of the number + * @return mantissa of the given number + */ + private static String getMantissa(final String str) { + return getMantissa(str, str.length()); + } + + /** + *

              Utility method for {@link #createNumber(java.lang.String)}.

              + * + *

              Returns mantissa of the given number.

              + * + * @param str the string representation of the number + * @param stopPos the position of the exponent or decimal point + * @return mantissa of the given number + */ + private static String getMantissa(final String str, final int stopPos) { + final char firstChar = str.charAt(0); + final boolean hasSign = firstChar == '-' || firstChar == '+'; + + return hasSign ? str.substring(1, stopPos) : str.substring(0, stopPos); + } + + /** + *

              Utility method for {@link #createNumber(java.lang.String)}.

              + * + *

              Returns true if s is null.

              + * + * @param str the String to check + * @return if it is all zeros or null + */ + private static boolean isAllZeros(final String str) { + if (str == null) { + return true; + } + for (int i = str.length() - 1; i >= 0; i--) { + if (str.charAt(i) != '0') { + return false; + } + } + return str.length() > 0; + } + + //----------------------------------------------------------------------- + /** + *

              Convert a String to a Float.

              + * + *

              Returns null if the string is null.

              + * + * @param str a String to convert, may be null + * @return converted Float (or null if the input is null) + * @throws NumberFormatException if the value cannot be converted + */ + public static Float createFloat(final String str) { + if (str == null) { + return null; + } + return Float.valueOf(str); + } + + /** + *

              Convert a String to a Double.

              + * + *

              Returns null if the string is null.

              + * + * @param str a String to convert, may be null + * @return converted Double (or null if the input is null) + * @throws NumberFormatException if the value cannot be converted + */ + public static Double createDouble(final String str) { + if (str == null) { + return null; + } + return Double.valueOf(str); + } + + /** + *

              Convert a String to a Integer, handling + * hex (0xhhhh) and octal (0dddd) notations. + * N.B. a leading zero means octal; spaces are not trimmed.

              + * + *

              Returns null if the string is null.

              + * + * @param str a String to convert, may be null + * @return converted Integer (or null if the input is null) + * @throws NumberFormatException if the value cannot be converted + */ + public static Integer createInteger(final String str) { + if (str == null) { + return null; + } + // decode() handles 0xAABD and 0777 (hex and octal) as well. + return Integer.decode(str); + } + + /** + *

              Convert a String to a Long; + * since 3.1 it handles hex (0Xhhhh) and octal (0ddd) notations. + * N.B. a leading zero means octal; spaces are not trimmed.

              + * + *

              Returns null if the string is null.

              + * + * @param str a String to convert, may be null + * @return converted Long (or null if the input is null) + * @throws NumberFormatException if the value cannot be converted + */ + public static Long createLong(final String str) { + if (str == null) { + return null; + } + return Long.decode(str); + } + + /** + *

              Convert a String to a BigInteger; + * since 3.2 it handles hex (0x or #) and octal (0) notations.

              + * + *

              Returns null if the string is null.

              + * + * @param str a String to convert, may be null + * @return converted BigInteger (or null if the input is null) + * @throws NumberFormatException if the value cannot be converted + */ + public static BigInteger createBigInteger(final String str) { + if (str == null) { + return null; + } + int pos = 0; // offset within string + int radix = 10; + boolean negate = false; // need to negate later? + if (str.startsWith("-")) { + negate = true; + pos = 1; + } + if (str.startsWith("0x", pos) || str.startsWith("0X", pos)) { // hex + radix = 16; + pos += 2; + } else if (str.startsWith("#", pos)) { // alternative hex (allowed by Long/Integer) + radix = 16; + pos ++; + } else if (str.startsWith("0", pos) && str.length() > pos + 1) { // octal; so long as there are additional digits + radix = 8; + pos ++; + } // default is to treat as decimal + + final BigInteger value = new BigInteger(str.substring(pos), radix); + return negate ? value.negate() : value; + } + + /** + *

              Convert a String to a BigDecimal.

              + * + *

              Returns null if the string is null.

              + * + * @param str a String to convert, may be null + * @return converted BigDecimal (or null if the input is null) + * @throws NumberFormatException if the value cannot be converted + */ + public static BigDecimal createBigDecimal(final String str) { + if (str == null) { + return null; + } + // handle JDK1.3.1 bug where "" throws IndexOutOfBoundsException + if (StringUtils.isBlank(str)) { + throw new NumberFormatException("A blank string is not a valid number"); + } + if (str.trim().startsWith("--")) { + // this is protection for poorness in java.lang.BigDecimal. + // it accepts this as a legal value, but it does not appear + // to be in specification of class. OS X Java parses it to + // a wrong value. + throw new NumberFormatException(str + " is not a valid number."); + } + return new BigDecimal(str); + } + + // Min in array + //-------------------------------------------------------------------- + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from min(long[]) to min(long...) + */ + public static long min(final long... array) { + // Validates input + validateArray(array); + + // Finds and returns min + long min = array[0]; + for (int i = 1; i < array.length; i++) { + if (array[i] < min) { + min = array[i]; + } + } + + return min; + } + + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from min(int[]) to min(int...) + */ + public static int min(final int... array) { + // Validates input + validateArray(array); + + // Finds and returns min + int min = array[0]; + for (int j = 1; j < array.length; j++) { + if (array[j] < min) { + min = array[j]; + } + } + + return min; + } + + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from min(short[]) to min(short...) + */ + public static short min(final short... array) { + // Validates input + validateArray(array); + + // Finds and returns min + short min = array[0]; + for (int i = 1; i < array.length; i++) { + if (array[i] < min) { + min = array[i]; + } + } + + return min; + } + + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from min(byte[]) to min(byte...) + */ + public static byte min(final byte... array) { + // Validates input + validateArray(array); + + // Finds and returns min + byte min = array[0]; + for (int i = 1; i < array.length; i++) { + if (array[i] < min) { + min = array[i]; + } + } + + return min; + } + + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @see IEEE754rUtils#min(double[]) IEEE754rUtils for a version of this method that handles NaN differently + * @since 3.4 Changed signature from min(double[]) to min(double...) + */ + public static double min(final double... array) { + // Validates input + validateArray(array); + + // Finds and returns min + double min = array[0]; + for (int i = 1; i < array.length; i++) { + if (Double.isNaN(array[i])) { + return Double.NaN; + } + if (array[i] < min) { + min = array[i]; + } + } + + return min; + } + + /** + *

              Returns the minimum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the minimum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @see IEEE754rUtils#min(float[]) IEEE754rUtils for a version of this method that handles NaN differently + * @since 3.4 Changed signature from min(float[]) to min(float...) + */ + public static float min(final float... array) { + // Validates input + validateArray(array); + + // Finds and returns min + float min = array[0]; + for (int i = 1; i < array.length; i++) { + if (Float.isNaN(array[i])) { + return Float.NaN; + } + if (array[i] < min) { + min = array[i]; + } + } + + return min; + } + + // Max in array + //-------------------------------------------------------------------- + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the maximum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from max(long[]) to max(long...) + */ + public static long max(final long... array) { + // Validates input + validateArray(array); + + // Finds and returns max + long max = array[0]; + for (int j = 1; j < array.length; j++) { + if (array[j] > max) { + max = array[j]; + } + } + + return max; + } + + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the maximum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from max(int[]) to max(int...) + */ + public static int max(final int... array) { + // Validates input + validateArray(array); + + // Finds and returns max + int max = array[0]; + for (int j = 1; j < array.length; j++) { + if (array[j] > max) { + max = array[j]; + } + } + + return max; + } + + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the maximum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from max(short[]) to max(short...) + */ + public static short max(final short... array) { + // Validates input + validateArray(array); + + // Finds and returns max + short max = array[0]; + for (int i = 1; i < array.length; i++) { + if (array[i] > max) { + max = array[i]; + } + } + + return max; + } + + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the maximum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @since 3.4 Changed signature from max(byte[]) to max(byte...) + */ + public static byte max(final byte... array) { + // Validates input + validateArray(array); + + // Finds and returns max + byte max = array[0]; + for (int i = 1; i < array.length; i++) { + if (array[i] > max) { + max = array[i]; + } + } + + return max; + } + + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the maximum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @see IEEE754rUtils#max(double[]) IEEE754rUtils for a version of this method that handles NaN differently + * @since 3.4 Changed signature from max(double[]) to max(double...) + */ + public static double max(final double... array) { + // Validates input + validateArray(array); + + // Finds and returns max + double max = array[0]; + for (int j = 1; j < array.length; j++) { + if (Double.isNaN(array[j])) { + return Double.NaN; + } + if (array[j] > max) { + max = array[j]; + } + } + + return max; + } + + /** + *

              Returns the maximum value in an array.

              + * + * @param array an array, must not be null or empty + * @return the maximum value in the array + * @throws IllegalArgumentException if array is null + * @throws IllegalArgumentException if array is empty + * @see IEEE754rUtils#max(float[]) IEEE754rUtils for a version of this method that handles NaN differently + * @since 3.4 Changed signature from max(float[]) to max(float...) + */ + public static float max(final float... array) { + // Validates input + validateArray(array); + + // Finds and returns max + float max = array[0]; + for (int j = 1; j < array.length; j++) { + if (Float.isNaN(array[j])) { + return Float.NaN; + } + if (array[j] > max) { + max = array[j]; + } + } + + return max; + } + + /** + * Checks if the specified array is neither null nor empty. + * + * @param array the array to check + * @throws IllegalArgumentException if {@code array} is either {@code null} or empty + */ + private static void validateArray(final Object array) { + if (array == null) { + throw new IllegalArgumentException("The Array must not be null"); + } + Validate.isTrue(Array.getLength(array) != 0, "Array cannot be empty."); + } + + // 3 param min + //----------------------------------------------------------------------- + /** + *

              Gets the minimum of three long values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + */ + public static long min(long a, final long b, final long c) { + if (b < a) { + a = b; + } + if (c < a) { + a = c; + } + return a; + } + + /** + *

              Gets the minimum of three int values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + */ + public static int min(int a, final int b, final int c) { + if (b < a) { + a = b; + } + if (c < a) { + a = c; + } + return a; + } + + /** + *

              Gets the minimum of three short values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + */ + public static short min(short a, final short b, final short c) { + if (b < a) { + a = b; + } + if (c < a) { + a = c; + } + return a; + } + + /** + *

              Gets the minimum of three byte values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + */ + public static byte min(byte a, final byte b, final byte c) { + if (b < a) { + a = b; + } + if (c < a) { + a = c; + } + return a; + } + + /** + *

              Gets the minimum of three double values.

              + * + *

              If any value is NaN, NaN is + * returned. Infinity is handled.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + * @see IEEE754rUtils#min(double, double, double) for a version of this method that handles NaN differently + */ + public static double min(final double a, final double b, final double c) { + return Math.min(Math.min(a, b), c); + } + + /** + *

              Gets the minimum of three float values.

              + * + *

              If any value is NaN, NaN is + * returned. Infinity is handled.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the smallest of the values + * @see IEEE754rUtils#min(float, float, float) for a version of this method that handles NaN differently + */ + public static float min(final float a, final float b, final float c) { + return Math.min(Math.min(a, b), c); + } + + // 3 param max + //----------------------------------------------------------------------- + /** + *

              Gets the maximum of three long values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + */ + public static long max(long a, final long b, final long c) { + if (b > a) { + a = b; + } + if (c > a) { + a = c; + } + return a; + } + + /** + *

              Gets the maximum of three int values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + */ + public static int max(int a, final int b, final int c) { + if (b > a) { + a = b; + } + if (c > a) { + a = c; + } + return a; + } + + /** + *

              Gets the maximum of three short values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + */ + public static short max(short a, final short b, final short c) { + if (b > a) { + a = b; + } + if (c > a) { + a = c; + } + return a; + } + + /** + *

              Gets the maximum of three byte values.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + */ + public static byte max(byte a, final byte b, final byte c) { + if (b > a) { + a = b; + } + if (c > a) { + a = c; + } + return a; + } + + /** + *

              Gets the maximum of three double values.

              + * + *

              If any value is NaN, NaN is + * returned. Infinity is handled.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + * @see IEEE754rUtils#max(double, double, double) for a version of this method that handles NaN differently + */ + public static double max(final double a, final double b, final double c) { + return Math.max(Math.max(a, b), c); + } + + /** + *

              Gets the maximum of three float values.

              + * + *

              If any value is NaN, NaN is + * returned. Infinity is handled.

              + * + * @param a value 1 + * @param b value 2 + * @param c value 3 + * @return the largest of the values + * @see IEEE754rUtils#max(float, float, float) for a version of this method that handles NaN differently + */ + public static float max(final float a, final float b, final float c) { + return Math.max(Math.max(a, b), c); + } + + //----------------------------------------------------------------------- + /** + *

              Checks whether the String contains only + * digit characters.

              + * + *

              Null and empty String will return + * false.

              + * + * @param str the String to check + * @return true if str contains only Unicode numeric + */ + public static boolean isDigits(final String str) { + return StringUtils.isNumeric(str); + } + + /** + *

              Checks whether the String a valid Java number.

              + * + *

              Valid numbers include hexadecimal marked with the 0x or + * 0X qualifier, octal numbers, scientific notation and + * numbers marked with a type qualifier (e.g. 123L).

              + * + *

              Non-hexadecimal strings beginning with a leading zero are + * treated as octal values. Thus the string 09 will return + * false, since 9 is not a valid octal value. + * However, numbers beginning with {@code 0.} are treated as decimal.

              + * + *

              null and empty/blank {@code String} will return + * false.

              + * + *

              Note, {@link #createNumber(String)} should return a number for every + * input resulting in true.

              + * + * @param str the String to check + * @return true if the string is a correctly formatted number + * @since 3.3 the code supports hex {@code 0Xhhh} an + * octal {@code 0ddd} validation + * @deprecated This feature will be removed in Lang 4.0, + * use {@link NumberUtils#isCreatable(String)} instead + */ + @Deprecated + public static boolean isNumber(final String str) { + return isCreatable(str); + } + + /** + *

              Checks whether the String a valid Java number.

              + * + *

              Valid numbers include hexadecimal marked with the 0x or + * 0X qualifier, octal numbers, scientific notation and + * numbers marked with a type qualifier (e.g. 123L).

              + * + *

              Non-hexadecimal strings beginning with a leading zero are + * treated as octal values. Thus the string 09 will return + * false, since 9 is not a valid octal value. + * However, numbers beginning with {@code 0.} are treated as decimal.

              + * + *

              null and empty/blank {@code String} will return + * false.

              + * + *

              Note, {@link #createNumber(String)} should return a number for every + * input resulting in true.

              + * + * @param str the String to check + * @return true if the string is a correctly formatted number + * @since 3.5 the code supports the "+" suffix on numbers except for integers in Java 1.6 + */ + public static boolean isCreatable(final String str) { + if (StringUtils.isEmpty(str)) { + return false; + } + final char[] chars = str.toCharArray(); + int sz = chars.length; + boolean hasExp = false; + boolean hasDecPoint = false; + boolean allowSigns = false; + boolean foundDigit = false; + // deal with any possible sign up front + final int start = chars[0] == '-' || chars[0] == '+' ? 1 : 0; + final boolean hasLeadingPlusSign = start == 1 && chars[0] == '+'; + if (sz > start + 1 && chars[start] == '0') { // leading 0 + if (chars[start + 1] == 'x' || chars[start + 1] == 'X') { // leading 0x/0X + int i = start + 2; + if (i == sz) { + return false; // str == "0x" + } + // checking hex (it can't be anything else) + for (; i < chars.length; i++) { + if ((chars[i] < '0' || chars[i] > '9') + && (chars[i] < 'a' || chars[i] > 'f') + && (chars[i] < 'A' || chars[i] > 'F')) { + return false; + } + } + return true; + } else if (Character.isDigit(chars[start + 1])) { + // leading 0, but not hex, must be octal + int i = start + 1; + for (; i < chars.length; i++) { + if (chars[i] < '0' || chars[i] > '7') { + return false; + } + } + return true; + } + } + sz--; // don't want to loop to the last char, check it afterwords + // for type qualifiers + int i = start; + // loop to the next to last char or to the last char if we need another digit to + // make a valid number (e.g. chars[0..5] = "1234E") + while (i < sz || i < sz + 1 && allowSigns && !foundDigit) { + if (chars[i] >= '0' && chars[i] <= '9') { + foundDigit = true; + allowSigns = false; + + } else if (chars[i] == '.') { + if (hasDecPoint || hasExp) { + // two decimal points or dec in exponent + return false; + } + hasDecPoint = true; + } else if (chars[i] == 'e' || chars[i] == 'E') { + // we've already taken care of hex. + if (hasExp) { + // two E's + return false; + } + if (!foundDigit) { + return false; + } + hasExp = true; + allowSigns = true; + } else if (chars[i] == '+' || chars[i] == '-') { + if (!allowSigns) { + return false; + } + allowSigns = false; + foundDigit = false; // we need a digit after the E + } else { + return false; + } + i++; + } + if (i < chars.length) { + if (chars[i] >= '0' && chars[i] <= '9') { + if (SystemUtils.IS_JAVA_1_6 && hasLeadingPlusSign && !hasDecPoint) { + return false; + } + // no type qualifier, OK + return true; + } + if (chars[i] == 'e' || chars[i] == 'E') { + // can't have an E at the last byte + return false; + } + if (chars[i] == '.') { + if (hasDecPoint || hasExp) { + // two decimal points or dec in exponent + return false; + } + // single trailing decimal point after non-exponent is ok + return foundDigit; + } + if (!allowSigns + && (chars[i] == 'd' + || chars[i] == 'D' + || chars[i] == 'f' + || chars[i] == 'F')) { + return foundDigit; + } + if (chars[i] == 'l' + || chars[i] == 'L') { + // not allowing L with an exponent or decimal point + return foundDigit && !hasExp && !hasDecPoint; + } + // last character is illegal + return false; + } + // allowSigns is true iff the val ends in 'E' + // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass + return !allowSigns && foundDigit; + } + + /** + *

              Checks whether the given String is a parsable number.

              + * + *

              Parsable numbers include those Strings understood by {@link Integer#parseInt(String)}, + * {@link Long#parseLong(String)}, {@link Float#parseFloat(String)} or + * {@link Double#parseDouble(String)}. This method can be used instead of catching {@link java.text.ParseException} + * when calling one of those methods.

              + * + *

              Hexadecimal and scientific notations are not considered parsable. + * See {@link #isCreatable(String)} on those cases.

              + * + *

              {@code Null} and empty String will return false.

              + * + * @param str the String to check. + * @return {@code true} if the string is a parsable number. + * @since 3.4 + */ + public static boolean isParsable(final String str) { + if (StringUtils.isEmpty(str)) { + return false; + } + if (str.charAt(str.length() - 1) == '.') { + return false; + } + if (str.charAt(0) == '-') { + if (str.length() == 1) { + return false; + } + return withDecimalsParsing(str, 1); + } else { + return withDecimalsParsing(str, 0); + } + } + + private static boolean withDecimalsParsing(final String str, final int beginIdx) { + int decimalPoints = 0; + for (int i = beginIdx; i < str.length(); i++) { + final boolean isDecimalPoint = str.charAt(i) == '.'; + if (isDecimalPoint) { + decimalPoints++; + } + if (decimalPoints > 1) { + return false; + } + if (!isDecimalPoint && !Character.isDigit(str.charAt(i))) { + return false; + } + } + return true; + } + + /** + *

              Compares two {@code int} values numerically. This is the same functionality as provided in Java 7.

              + * + * @param x the first {@code int} to compare + * @param y the second {@code int} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(final int x, final int y) { + if (x == y) { + return 0; + } + return x < y ? -1 : 1; + } + + /** + *

              Compares to {@code long} values numerically. This is the same functionality as provided in Java 7.

              + * + * @param x the first {@code long} to compare + * @param y the second {@code long} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(final long x, final long y) { + if (x == y) { + return 0; + } + return x < y ? -1 : 1; + } + + /** + *

              Compares to {@code short} values numerically. This is the same functionality as provided in Java 7.

              + * + * @param x the first {@code short} to compare + * @param y the second {@code short} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(final short x, final short y) { + if (x == y) { + return 0; + } + return x < y ? -1 : 1; + } + + /** + *

              Compares two {@code byte} values numerically. This is the same functionality as provided in Java 7.

              + * + * @param x the first {@code byte} to compare + * @param y the second {@code byte} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(final byte x, final byte y) { + return x - y; + } +} diff --git a/src/org/apache/commons/lang3/math/package-info.java b/src/org/apache/commons/lang3/math/package-info.java new file mode 100644 index 0000000..16ca5b2 --- /dev/null +++ b/src/org/apache/commons/lang3/math/package-info.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Extends {@link java.math} for business mathematical classes. + * This package is intended for business mathematical use, not scientific use. + * See Commons Math for a more complete set of mathematical classes. + * These classes are immutable, and therefore thread-safe.

              + * + *

              Although Commons Math also exists, some basic mathematical functions are contained within Lang. + * These include classes to a {@link org.apache.commons.lang3.math.Fraction} class, various utilities for random numbers, and the flagship class, {@link org.apache.commons.lang3.math.NumberUtils} which contains a handful of classic number functions.

              + * + *

              There are two aspects of this package that should be highlighted. + * The first is {@link org.apache.commons.lang3.math.NumberUtils#createNumber(String)}, a method which does its best to convert a String into a {@link java.lang.Number} object. + * You have no idea what type of Number it will return, so you should call the relevant xxxValue method when you reach the point of needing a number. + * NumberUtils also has a related {@link org.apache.commons.lang3.math.NumberUtils#isCreatable(String)} method.

              + * + * @since 2.0 + */ +package org.apache.commons.lang3.math; diff --git a/src/org/apache/commons/lang3/mutable/Mutable.java b/src/org/apache/commons/lang3/mutable/Mutable.java new file mode 100644 index 0000000..301cac2 --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/Mutable.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.mutable; + +/** + * Provides mutable access to a value. + *

              + * Mutable is used as a generic interface to the implementations in this package. + *

              + * A typical use case would be to enable a primitive or string to be passed to a method and allow that method to + * effectively change the value of the primitive/string. Another use case is to store a frequently changing primitive in + * a collection (for example a total in a map) without needing to create new Integer/Long wrapper objects. + * + * @param the type to set and get + * @since 2.1 + */ +public interface Mutable { + + /** + * Gets the value of this mutable. + * + * @return the stored value + */ + T getValue(); + + /** + * Sets the value of this mutable. + * + * @param value + * the value to store + * @throws NullPointerException + * if the object is null and null is invalid + * @throws ClassCastException + * if the type is invalid + */ + void setValue(T value); + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableBoolean.java b/src/org/apache/commons/lang3/mutable/MutableBoolean.java new file mode 100644 index 0000000..97781bf --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableBoolean.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.mutable; + +import java.io.Serializable; + +import org.apache.commons.lang3.BooleanUtils; + +/** + * A mutable boolean wrapper. + *

              + * Note that as MutableBoolean does not extend Boolean, it is not treated by String.format as a Boolean parameter. + * + * @see Boolean + * @since 2.2 + */ +public class MutableBoolean implements Mutable, Serializable, Comparable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = -4830728138360036487L; + + /** The mutable value. */ + private boolean value; + + /** + * Constructs a new MutableBoolean with the default value of false. + */ + public MutableBoolean() { + super(); + } + + /** + * Constructs a new MutableBoolean with the specified value. + * + * @param value the initial value to store + */ + public MutableBoolean(final boolean value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableBoolean with the specified value. + * + * @param value the initial value to store, not null + * @throws NullPointerException if the object is null + */ + public MutableBoolean(final Boolean value) { + super(); + this.value = value.booleanValue(); + } + + //----------------------------------------------------------------------- + /** + * Gets the value as a Boolean instance. + * + * @return the value as a Boolean, never null + */ + @Override + public Boolean getValue() { + return Boolean.valueOf(this.value); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(final boolean value) { + this.value = value; + } + + /** + * Sets the value to false. + * + * @since 3.3 + */ + public void setFalse() { + this.value = false; + } + + /** + * Sets the value to true. + * + * @since 3.3 + */ + public void setTrue() { + this.value = true; + } + + /** + * Sets the value from any Boolean instance. + * + * @param value the value to set, not null + * @throws NullPointerException if the object is null + */ + @Override + public void setValue(final Boolean value) { + this.value = value.booleanValue(); + } + + //----------------------------------------------------------------------- + /** + * Checks if the current value is true. + * + * @return true if the current value is true + * @since 2.5 + */ + public boolean isTrue() { + return value == true; + } + + /** + * Checks if the current value is false. + * + * @return true if the current value is false + * @since 2.5 + */ + public boolean isFalse() { + return value == false; + } + + //----------------------------------------------------------------------- + /** + * Returns the value of this MutableBoolean as a boolean. + * + * @return the boolean value represented by this object. + */ + public boolean booleanValue() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Gets this mutable as an instance of Boolean. + * + * @return a Boolean instance containing the value from this mutable, never null + * @since 2.5 + */ + public Boolean toBoolean() { + return Boolean.valueOf(booleanValue()); + } + + //----------------------------------------------------------------------- + /** + * Compares this object to the specified object. The result is true if and only if the argument is + * not null and is an MutableBoolean object that contains the same + * boolean value as this object. + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableBoolean) { + return value == ((MutableBoolean) obj).booleanValue(); + } + return false; + } + + /** + * Returns a suitable hash code for this mutable. + * + * @return the hash code returned by Boolean.TRUE or Boolean.FALSE + */ + @Override + public int hashCode() { + return value ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Compares this mutable to another in ascending order. + * + * @param other the other mutable to compare to, not null + * @return negative if this is less, zero if equal, positive if greater + * where false is less than true + */ + @Override + public int compareTo(final MutableBoolean other) { + return BooleanUtils.compare(this.value, other.value); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return String.valueOf(value); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableByte.java b/src/org/apache/commons/lang3/mutable/MutableByte.java new file mode 100644 index 0000000..5ceb9bb --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableByte.java @@ -0,0 +1,392 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.mutable; + +import org.apache.commons.lang3.math.NumberUtils; + +/** + * A mutable byte wrapper. + *

              + * Note that as MutableByte does not extend Byte, it is not treated by String.format as a Byte parameter. + * + * @see Byte + * @since 2.1 + */ +public class MutableByte extends Number implements Comparable, Mutable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = -1585823265L; + + /** The mutable value. */ + private byte value; + + /** + * Constructs a new MutableByte with the default value of zero. + */ + public MutableByte() { + super(); + } + + /** + * Constructs a new MutableByte with the specified value. + * + * @param value the initial value to store + */ + public MutableByte(final byte value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableByte with the specified value. + * + * @param value the initial value to store, not null + * @throws NullPointerException if the object is null + */ + public MutableByte(final Number value) { + super(); + this.value = value.byteValue(); + } + + /** + * Constructs a new MutableByte parsing the given string. + * + * @param value the string to parse, not null + * @throws NumberFormatException if the string cannot be parsed into a byte + * @since 2.5 + */ + public MutableByte(final String value) throws NumberFormatException { + super(); + this.value = Byte.parseByte(value); + } + + //----------------------------------------------------------------------- + /** + * Gets the value as a Byte instance. + * + * @return the value as a Byte, never null + */ + @Override + public Byte getValue() { + return Byte.valueOf(this.value); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(final byte value) { + this.value = value; + } + + /** + * Sets the value from any Number instance. + * + * @param value the value to set, not null + * @throws NullPointerException if the object is null + */ + @Override + public void setValue(final Number value) { + this.value = value.byteValue(); + } + + //----------------------------------------------------------------------- + /** + * Increments the value. + * + * @since Commons Lang 2.2 + */ + public void increment() { + value++; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the increment operation. This method is not thread safe. + * + * @return the value associated with the instance before it was incremented + * @since 3.5 + */ + public byte getAndIncrement() { + final byte last = value; + value++; + return last; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately after the increment operation. This method is not thread safe. + * + * @return the value associated with the instance after it is incremented + * @since 3.5 + */ + public byte incrementAndGet() { + value++; + return value; + } + + /** + * Decrements the value. + * + * @since Commons Lang 2.2 + */ + public void decrement() { + value--; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance before it was decremented + * @since 3.5 + */ + public byte getAndDecrement() { + final byte last = value; + value--; + return last; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately after the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance after it is decremented + * @since 3.5 + */ + public byte decrementAndGet() { + value--; + return value; + } + + //----------------------------------------------------------------------- + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @since Commons Lang 2.2 + */ + public void add(final byte operand) { + this.value += operand; + } + + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void add(final Number operand) { + this.value += operand.byteValue(); + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @since Commons Lang 2.2 + */ + public void subtract(final byte operand) { + this.value -= operand; + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void subtract(final Number operand) { + this.value -= operand.byteValue(); + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public byte addAndGet(final byte operand) { + this.value += operand; + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public byte addAndGet(final Number operand) { + this.value += operand.byteValue(); + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public byte getAndAdd(final byte operand) { + final byte last = value; + this.value += operand; + return last; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public byte getAndAdd(final Number operand) { + final byte last = value; + this.value += operand.byteValue(); + return last; + } + + //----------------------------------------------------------------------- + // shortValue relies on Number implementation + /** + * Returns the value of this MutableByte as a byte. + * + * @return the numeric value represented by this object after conversion to type byte. + */ + @Override + public byte byteValue() { + return value; + } + + /** + * Returns the value of this MutableByte as an int. + * + * @return the numeric value represented by this object after conversion to type int. + */ + @Override + public int intValue() { + return value; + } + + /** + * Returns the value of this MutableByte as a long. + * + * @return the numeric value represented by this object after conversion to type long. + */ + @Override + public long longValue() { + return value; + } + + /** + * Returns the value of this MutableByte as a float. + * + * @return the numeric value represented by this object after conversion to type float. + */ + @Override + public float floatValue() { + return value; + } + + /** + * Returns the value of this MutableByte as a double. + * + * @return the numeric value represented by this object after conversion to type double. + */ + @Override + public double doubleValue() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Gets this mutable as an instance of Byte. + * + * @return a Byte instance containing the value from this mutable + */ + public Byte toByte() { + return Byte.valueOf(byteValue()); + } + + //----------------------------------------------------------------------- + /** + * Compares this object to the specified object. The result is true if and only if the argument is + * not null and is a MutableByte object that contains the same byte value + * as this object. + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableByte) { + return value == ((MutableByte) obj).byteValue(); + } + return false; + } + + /** + * Returns a suitable hash code for this mutable. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Compares this mutable to another in ascending order. + * + * @param other the other mutable to compare to, not null + * @return negative if this is less, zero if equal, positive if greater + */ + @Override + public int compareTo(final MutableByte other) { + return NumberUtils.compare(this.value, other.value); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return String.valueOf(value); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableDouble.java b/src/org/apache/commons/lang3/mutable/MutableDouble.java new file mode 100644 index 0000000..cd89027 --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableDouble.java @@ -0,0 +1,419 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.mutable; + +/** + * A mutable double wrapper. + *

              + * Note that as MutableDouble does not extend Double, it is not treated by String.format as a Double parameter. + * + * @see Double + * @since 2.1 + */ +public class MutableDouble extends Number implements Comparable, Mutable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1587163916L; + + /** The mutable value. */ + private double value; + + /** + * Constructs a new MutableDouble with the default value of zero. + */ + public MutableDouble() { + super(); + } + + /** + * Constructs a new MutableDouble with the specified value. + * + * @param value the initial value to store + */ + public MutableDouble(final double value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableDouble with the specified value. + * + * @param value the initial value to store, not null + * @throws NullPointerException if the object is null + */ + public MutableDouble(final Number value) { + super(); + this.value = value.doubleValue(); + } + + /** + * Constructs a new MutableDouble parsing the given string. + * + * @param value the string to parse, not null + * @throws NumberFormatException if the string cannot be parsed into a double + * @since 2.5 + */ + public MutableDouble(final String value) throws NumberFormatException { + super(); + this.value = Double.parseDouble(value); + } + + //----------------------------------------------------------------------- + /** + * Gets the value as a Double instance. + * + * @return the value as a Double, never null + */ + @Override + public Double getValue() { + return Double.valueOf(this.value); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(final double value) { + this.value = value; + } + + /** + * Sets the value from any Number instance. + * + * @param value the value to set, not null + * @throws NullPointerException if the object is null + */ + @Override + public void setValue(final Number value) { + this.value = value.doubleValue(); + } + + //----------------------------------------------------------------------- + /** + * Checks whether the double value is the special NaN value. + * + * @return true if NaN + */ + public boolean isNaN() { + return Double.isNaN(value); + } + + /** + * Checks whether the double value is infinite. + * + * @return true if infinite + */ + public boolean isInfinite() { + return Double.isInfinite(value); + } + + //----------------------------------------------------------------------- + /** + * Increments the value. + * + * @since Commons Lang 2.2 + */ + public void increment() { + value++; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the increment operation. This method is not thread safe. + * + * @return the value associated with the instance before it was incremented + * @since 3.5 + */ + public double getAndIncrement() { + final double last = value; + value++; + return last; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately after the increment operation. This method is not thread safe. + * + * @return the value associated with the instance after it is incremented + * @since 3.5 + */ + public double incrementAndGet() { + value++; + return value; + } + + /** + * Decrements the value. + * + * @since Commons Lang 2.2 + */ + public void decrement() { + value--; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance before it was decremented + * @since 3.5 + */ + public double getAndDecrement() { + final double last = value; + value--; + return last; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately after the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance after it is decremented + * @since 3.5 + */ + public double decrementAndGet() { + value--; + return value; + } + + //----------------------------------------------------------------------- + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add + * @since Commons Lang 2.2 + */ + public void add(final double operand) { + this.value += operand; + } + + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void add(final Number operand) { + this.value += operand.doubleValue(); + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @since Commons Lang 2.2 + */ + public void subtract(final double operand) { + this.value -= operand; + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void subtract(final Number operand) { + this.value -= operand.doubleValue(); + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public double addAndGet(final double operand) { + this.value += operand; + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public double addAndGet(final Number operand) { + this.value += operand.doubleValue(); + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public double getAndAdd(final double operand) { + final double last = value; + this.value += operand; + return last; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public double getAndAdd(final Number operand) { + final double last = value; + this.value += operand.doubleValue(); + return last; + } + + //----------------------------------------------------------------------- + // shortValue and byteValue rely on Number implementation + /** + * Returns the value of this MutableDouble as an int. + * + * @return the numeric value represented by this object after conversion to type int. + */ + @Override + public int intValue() { + return (int) value; + } + + /** + * Returns the value of this MutableDouble as a long. + * + * @return the numeric value represented by this object after conversion to type long. + */ + @Override + public long longValue() { + return (long) value; + } + + /** + * Returns the value of this MutableDouble as a float. + * + * @return the numeric value represented by this object after conversion to type float. + */ + @Override + public float floatValue() { + return (float) value; + } + + /** + * Returns the value of this MutableDouble as a double. + * + * @return the numeric value represented by this object after conversion to type double. + */ + @Override + public double doubleValue() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Gets this mutable as an instance of Double. + * + * @return a Double instance containing the value from this mutable, never null + */ + public Double toDouble() { + return Double.valueOf(doubleValue()); + } + + //----------------------------------------------------------------------- + /** + * Compares this object against the specified object. The result is true if and only if the argument + * is not null and is a Double object that represents a double that has the identical + * bit pattern to the bit pattern of the double represented by this object. For this purpose, two + * double values are considered to be the same if and only if the method + * {@link Double#doubleToLongBits(double)}returns the same long value when applied to each. + *

              + * Note that in most cases, for two instances of class Double,d1 and d2, + * the value of d1.equals(d2) is true if and only if

              + * + *
              +     *   d1.doubleValue() == d2.doubleValue()
              +     * 
              + * + *
              + *

              + * also has the value true. However, there are two exceptions: + *

                + *
              • If d1 and d2 both represent Double.NaN, then the + * equals method returns true, even though Double.NaN==Double.NaN has + * the value false. + *
              • If d1 represents +0.0 while d2 represents -0.0, + * or vice versa, the equal test has the value false, even though + * +0.0==-0.0 has the value true. This allows hashtables to operate properly. + *
              + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; false otherwise. + */ + @Override + public boolean equals(final Object obj) { + return obj instanceof MutableDouble + && Double.doubleToLongBits(((MutableDouble) obj).value) == Double.doubleToLongBits(value); + } + + /** + * Returns a suitable hash code for this mutable. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + final long bits = Double.doubleToLongBits(value); + return (int) (bits ^ bits >>> 32); + } + + //----------------------------------------------------------------------- + /** + * Compares this mutable to another in ascending order. + * + * @param other the other mutable to compare to, not null + * @return negative if this is less, zero if equal, positive if greater + */ + @Override + public int compareTo(final MutableDouble other) { + return Double.compare(this.value, other.value); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return String.valueOf(value); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableFloat.java b/src/org/apache/commons/lang3/mutable/MutableFloat.java new file mode 100644 index 0000000..6ed0980 --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableFloat.java @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.mutable; + +/** + * A mutable float wrapper. + *

              + * Note that as MutableFloat does not extend Float, it is not treated by String.format as a Float parameter. + * + * @see Float + * @since 2.1 + */ +public class MutableFloat extends Number implements Comparable, Mutable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 5787169186L; + + /** The mutable value. */ + private float value; + + /** + * Constructs a new MutableFloat with the default value of zero. + */ + public MutableFloat() { + super(); + } + + /** + * Constructs a new MutableFloat with the specified value. + * + * @param value the initial value to store + */ + public MutableFloat(final float value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableFloat with the specified value. + * + * @param value the initial value to store, not null + * @throws NullPointerException if the object is null + */ + public MutableFloat(final Number value) { + super(); + this.value = value.floatValue(); + } + + /** + * Constructs a new MutableFloat parsing the given string. + * + * @param value the string to parse, not null + * @throws NumberFormatException if the string cannot be parsed into a float + * @since 2.5 + */ + public MutableFloat(final String value) throws NumberFormatException { + super(); + this.value = Float.parseFloat(value); + } + + //----------------------------------------------------------------------- + /** + * Gets the value as a Float instance. + * + * @return the value as a Float, never null + */ + @Override + public Float getValue() { + return Float.valueOf(this.value); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(final float value) { + this.value = value; + } + + /** + * Sets the value from any Number instance. + * + * @param value the value to set, not null + * @throws NullPointerException if the object is null + */ + @Override + public void setValue(final Number value) { + this.value = value.floatValue(); + } + + //----------------------------------------------------------------------- + /** + * Checks whether the float value is the special NaN value. + * + * @return true if NaN + */ + public boolean isNaN() { + return Float.isNaN(value); + } + + /** + * Checks whether the float value is infinite. + * + * @return true if infinite + */ + public boolean isInfinite() { + return Float.isInfinite(value); + } + + //----------------------------------------------------------------------- + /** + * Increments the value. + * + * @since Commons Lang 2.2 + */ + public void increment() { + value++; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the increment operation. This method is not thread safe. + * + * @return the value associated with the instance before it was incremented + * @since 3.5 + */ + public float getAndIncrement() { + final float last = value; + value++; + return last; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately after the increment operation. This method is not thread safe. + * + * @return the value associated with the instance after it is incremented + * @since 3.5 + */ + public float incrementAndGet() { + value++; + return value; + } + + /** + * Decrements the value. + * + * @since Commons Lang 2.2 + */ + public void decrement() { + value--; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance before it was decremented + * @since 3.5 + */ + public float getAndDecrement() { + final float last = value; + value--; + return last; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately after the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance after it is decremented + * @since 3.5 + */ + public float decrementAndGet() { + value--; + return value; + } + + //----------------------------------------------------------------------- + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @since Commons Lang 2.2 + */ + public void add(final float operand) { + this.value += operand; + } + + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void add(final Number operand) { + this.value += operand.floatValue(); + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract + * @since Commons Lang 2.2 + */ + public void subtract(final float operand) { + this.value -= operand; + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void subtract(final Number operand) { + this.value -= operand.floatValue(); + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public float addAndGet(final float operand) { + this.value += operand; + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public float addAndGet(final Number operand) { + this.value += operand.floatValue(); + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public float getAndAdd(final float operand) { + final float last = value; + this.value += operand; + return last; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public float getAndAdd(final Number operand) { + final float last = value; + this.value += operand.floatValue(); + return last; + } + + //----------------------------------------------------------------------- + // shortValue and byteValue rely on Number implementation + /** + * Returns the value of this MutableFloat as an int. + * + * @return the numeric value represented by this object after conversion to type int. + */ + @Override + public int intValue() { + return (int) value; + } + + /** + * Returns the value of this MutableFloat as a long. + * + * @return the numeric value represented by this object after conversion to type long. + */ + @Override + public long longValue() { + return (long) value; + } + + /** + * Returns the value of this MutableFloat as a float. + * + * @return the numeric value represented by this object after conversion to type float. + */ + @Override + public float floatValue() { + return value; + } + + /** + * Returns the value of this MutableFloat as a double. + * + * @return the numeric value represented by this object after conversion to type double. + */ + @Override + public double doubleValue() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Gets this mutable as an instance of Float. + * + * @return a Float instance containing the value from this mutable, never null + */ + public Float toFloat() { + return Float.valueOf(floatValue()); + } + + //----------------------------------------------------------------------- + /** + * Compares this object against some other object. The result is true if and only if the argument is + * not null and is a Float object that represents a float that has the + * identical bit pattern to the bit pattern of the float represented by this object. For this + * purpose, two float values are considered to be the same if and only if the method + * {@link Float#floatToIntBits(float)}returns the same int value when applied to each. + *

              + * Note that in most cases, for two instances of class Float,f1 and f2, + * the value of f1.equals(f2) is true if and only if

              + * + *
              +     *   f1.floatValue() == f2.floatValue()
              +     * 
              + * + *
              + *

              + * also has the value true. However, there are two exceptions: + *

                + *
              • If f1 and f2 both represent Float.NaN, then the + * equals method returns true, even though Float.NaN==Float.NaN has + * the value false. + *
              • If f1 represents +0.0f while f2 represents -0.0f, + * or vice versa, the equal test has the value false, even though + * 0.0f==-0.0f has the value true. + *
              + * This definition allows hashtables to operate properly. + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; false otherwise. + * @see java.lang.Float#floatToIntBits(float) + */ + @Override + public boolean equals(final Object obj) { + return obj instanceof MutableFloat + && Float.floatToIntBits(((MutableFloat) obj).value) == Float.floatToIntBits(value); + } + + /** + * Returns a suitable hash code for this mutable. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return Float.floatToIntBits(value); + } + + //----------------------------------------------------------------------- + /** + * Compares this mutable to another in ascending order. + * + * @param other the other mutable to compare to, not null + * @return negative if this is less, zero if equal, positive if greater + */ + @Override + public int compareTo(final MutableFloat other) { + return Float.compare(this.value, other.value); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return String.valueOf(value); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableInt.java b/src/org/apache/commons/lang3/mutable/MutableInt.java new file mode 100644 index 0000000..7311f00 --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableInt.java @@ -0,0 +1,382 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.mutable; + +import org.apache.commons.lang3.math.NumberUtils; + +/** + * A mutable int wrapper. + *

              + * Note that as MutableInt does not extend Integer, it is not treated by String.format as an Integer parameter. + * + * @see Integer + * @since 2.1 + */ +public class MutableInt extends Number implements Comparable, Mutable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 512176391864L; + + /** The mutable value. */ + private int value; + + /** + * Constructs a new MutableInt with the default value of zero. + */ + public MutableInt() { + super(); + } + + /** + * Constructs a new MutableInt with the specified value. + * + * @param value the initial value to store + */ + public MutableInt(final int value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableInt with the specified value. + * + * @param value the initial value to store, not null + * @throws NullPointerException if the object is null + */ + public MutableInt(final Number value) { + super(); + this.value = value.intValue(); + } + + /** + * Constructs a new MutableInt parsing the given string. + * + * @param value the string to parse, not null + * @throws NumberFormatException if the string cannot be parsed into an int + * @since 2.5 + */ + public MutableInt(final String value) throws NumberFormatException { + super(); + this.value = Integer.parseInt(value); + } + + //----------------------------------------------------------------------- + /** + * Gets the value as a Integer instance. + * + * @return the value as a Integer, never null + */ + @Override + public Integer getValue() { + return Integer.valueOf(this.value); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(final int value) { + this.value = value; + } + + /** + * Sets the value from any Number instance. + * + * @param value the value to set, not null + * @throws NullPointerException if the object is null + */ + @Override + public void setValue(final Number value) { + this.value = value.intValue(); + } + + //----------------------------------------------------------------------- + /** + * Increments the value. + * + * @since Commons Lang 2.2 + */ + public void increment() { + value++; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the increment operation. This method is not thread safe. + * + * @return the value associated with the instance before it was incremented + * @since 3.5 + */ + public int getAndIncrement() { + final int last = value; + value++; + return last; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately after the increment operation. This method is not thread safe. + * + * @return the value associated with the instance after it is incremented + * @since 3.5 + */ + public int incrementAndGet() { + value++; + return value; + } + + /** + * Decrements the value. + * + * @since Commons Lang 2.2 + */ + public void decrement() { + value--; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance before it was decremented + * @since 3.5 + */ + public int getAndDecrement() { + final int last = value; + value--; + return last; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately after the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance after it is decremented + * @since 3.5 + */ + public int decrementAndGet() { + value--; + return value; + } + + //----------------------------------------------------------------------- + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @since Commons Lang 2.2 + */ + public void add(final int operand) { + this.value += operand; + } + + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void add(final Number operand) { + this.value += operand.intValue(); + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @since Commons Lang 2.2 + */ + public void subtract(final int operand) { + this.value -= operand; + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void subtract(final Number operand) { + this.value -= operand.intValue(); + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public int addAndGet(final int operand) { + this.value += operand; + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public int addAndGet(final Number operand) { + this.value += operand.intValue(); + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public int getAndAdd(final int operand) { + final int last = value; + this.value += operand; + return last; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public int getAndAdd(final Number operand) { + final int last = value; + this.value += operand.intValue(); + return last; + } + + //----------------------------------------------------------------------- + // shortValue and byteValue rely on Number implementation + /** + * Returns the value of this MutableInt as an int. + * + * @return the numeric value represented by this object after conversion to type int. + */ + @Override + public int intValue() { + return value; + } + + /** + * Returns the value of this MutableInt as a long. + * + * @return the numeric value represented by this object after conversion to type long. + */ + @Override + public long longValue() { + return value; + } + + /** + * Returns the value of this MutableInt as a float. + * + * @return the numeric value represented by this object after conversion to type float. + */ + @Override + public float floatValue() { + return value; + } + + /** + * Returns the value of this MutableInt as a double. + * + * @return the numeric value represented by this object after conversion to type double. + */ + @Override + public double doubleValue() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Gets this mutable as an instance of Integer. + * + * @return a Integer instance containing the value from this mutable, never null + */ + public Integer toInteger() { + return Integer.valueOf(intValue()); + } + + //----------------------------------------------------------------------- + /** + * Compares this object to the specified object. The result is true if and only if the argument is + * not null and is a MutableInt object that contains the same int value + * as this object. + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableInt) { + return value == ((MutableInt) obj).intValue(); + } + return false; + } + + /** + * Returns a suitable hash code for this mutable. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Compares this mutable to another in ascending order. + * + * @param other the other mutable to compare to, not null + * @return negative if this is less, zero if equal, positive if greater + */ + @Override + public int compareTo(final MutableInt other) { + return NumberUtils.compare(this.value, other.value); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return String.valueOf(value); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableLong.java b/src/org/apache/commons/lang3/mutable/MutableLong.java new file mode 100644 index 0000000..5b6254a --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableLong.java @@ -0,0 +1,382 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.mutable; + +import org.apache.commons.lang3.math.NumberUtils; + +/** + * A mutable long wrapper. + *

              + * Note that as MutableLong does not extend Long, it is not treated by String.format as a Long parameter. + * + * @see Long + * @since 2.1 + */ +public class MutableLong extends Number implements Comparable, Mutable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 62986528375L; + + /** The mutable value. */ + private long value; + + /** + * Constructs a new MutableLong with the default value of zero. + */ + public MutableLong() { + super(); + } + + /** + * Constructs a new MutableLong with the specified value. + * + * @param value the initial value to store + */ + public MutableLong(final long value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableLong with the specified value. + * + * @param value the initial value to store, not null + * @throws NullPointerException if the object is null + */ + public MutableLong(final Number value) { + super(); + this.value = value.longValue(); + } + + /** + * Constructs a new MutableLong parsing the given string. + * + * @param value the string to parse, not null + * @throws NumberFormatException if the string cannot be parsed into a long + * @since 2.5 + */ + public MutableLong(final String value) throws NumberFormatException { + super(); + this.value = Long.parseLong(value); + } + + //----------------------------------------------------------------------- + /** + * Gets the value as a Long instance. + * + * @return the value as a Long, never null + */ + @Override + public Long getValue() { + return Long.valueOf(this.value); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(final long value) { + this.value = value; + } + + /** + * Sets the value from any Number instance. + * + * @param value the value to set, not null + * @throws NullPointerException if the object is null + */ + @Override + public void setValue(final Number value) { + this.value = value.longValue(); + } + + //----------------------------------------------------------------------- + /** + * Increments the value. + * + * @since Commons Lang 2.2 + */ + public void increment() { + value++; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the increment operation. This method is not thread safe. + * + * @return the value associated with the instance before it was incremented + * @since 3.5 + */ + public long getAndIncrement() { + final long last = value; + value++; + return last; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately after the increment operation. This method is not thread safe. + * + * @return the value associated with the instance after it is incremented + * @since 3.5 + */ + public long incrementAndGet() { + value++; + return value; + } + + /** + * Decrements the value. + * + * @since Commons Lang 2.2 + */ + public void decrement() { + value--; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance before it was decremented + * @since 3.5 + */ + public long getAndDecrement() { + final long last = value; + value--; + return last; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately after the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance after it is decremented + * @since 3.5 + */ + public long decrementAndGet() { + value--; + return value; + } + + //----------------------------------------------------------------------- + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @since Commons Lang 2.2 + */ + public void add(final long operand) { + this.value += operand; + } + + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void add(final Number operand) { + this.value += operand.longValue(); + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @since Commons Lang 2.2 + */ + public void subtract(final long operand) { + this.value -= operand; + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void subtract(final Number operand) { + this.value -= operand.longValue(); + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public long addAndGet(final long operand) { + this.value += operand; + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public long addAndGet(final Number operand) { + this.value += operand.longValue(); + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public long getAndAdd(final long operand) { + final long last = value; + this.value += operand; + return last; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public long getAndAdd(final Number operand) { + final long last = value; + this.value += operand.longValue(); + return last; + } + + //----------------------------------------------------------------------- + // shortValue and byteValue rely on Number implementation + /** + * Returns the value of this MutableLong as an int. + * + * @return the numeric value represented by this object after conversion to type int. + */ + @Override + public int intValue() { + return (int) value; + } + + /** + * Returns the value of this MutableLong as a long. + * + * @return the numeric value represented by this object after conversion to type long. + */ + @Override + public long longValue() { + return value; + } + + /** + * Returns the value of this MutableLong as a float. + * + * @return the numeric value represented by this object after conversion to type float. + */ + @Override + public float floatValue() { + return value; + } + + /** + * Returns the value of this MutableLong as a double. + * + * @return the numeric value represented by this object after conversion to type double. + */ + @Override + public double doubleValue() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Gets this mutable as an instance of Long. + * + * @return a Long instance containing the value from this mutable, never null + */ + public Long toLong() { + return Long.valueOf(longValue()); + } + + //----------------------------------------------------------------------- + /** + * Compares this object to the specified object. The result is true if and only if the argument + * is not null and is a MutableLong object that contains the same long + * value as this object. + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableLong) { + return value == ((MutableLong) obj).longValue(); + } + return false; + } + + /** + * Returns a suitable hash code for this mutable. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return (int) (value ^ (value >>> 32)); + } + + //----------------------------------------------------------------------- + /** + * Compares this mutable to another in ascending order. + * + * @param other the other mutable to compare to, not null + * @return negative if this is less, zero if equal, positive if greater + */ + @Override + public int compareTo(final MutableLong other) { + return NumberUtils.compare(this.value, other.value); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return String.valueOf(value); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableObject.java b/src/org/apache/commons/lang3/mutable/MutableObject.java new file mode 100644 index 0000000..180cf3a --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableObject.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.lang3.mutable; + +import java.io.Serializable; + +/** + * A mutable Object wrapper. + * + * @param the type to set and get + * @since 2.1 + */ +public class MutableObject implements Mutable, Serializable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 86241875189L; + + /** The mutable value. */ + private T value; + + /** + * Constructs a new MutableObject with the default value of null. + */ + public MutableObject() { + super(); + } + + /** + * Constructs a new MutableObject with the specified value. + * + * @param value the initial value to store + */ + public MutableObject(final T value) { + super(); + this.value = value; + } + + //----------------------------------------------------------------------- + /** + * Gets the value. + * + * @return the value, may be null + */ + @Override + public T getValue() { + return this.value; + } + + /** + * Sets the value. + * + * @param value the value to set + */ + @Override + public void setValue(final T value) { + this.value = value; + } + + //----------------------------------------------------------------------- + /** + *

              + * Compares this object against the specified object. The result is true if and only if the argument + * is not null and is a MutableObject object that contains the same T + * value as this object. + *

              + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; + * true if the objects have equivalent value fields; + * false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (this.getClass() == obj.getClass()) { + final MutableObject that = (MutableObject) obj; + return this.value.equals(that.value); + } + return false; + } + + /** + * Returns the value's hash code or 0 if the value is null. + * + * @return the value's hash code or 0 if the value is null. + */ + @Override + public int hashCode() { + return value == null ? 0 : value.hashCode(); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return value == null ? "null" : value.toString(); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/MutableShort.java b/src/org/apache/commons/lang3/mutable/MutableShort.java new file mode 100644 index 0000000..01d604f --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/MutableShort.java @@ -0,0 +1,392 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.mutable; + +import org.apache.commons.lang3.math.NumberUtils; + +/** + * A mutable short wrapper. + *

              + * Note that as MutableShort does not extend Short, it is not treated by String.format as a Short parameter. + * + * @see Short + * @since 2.1 + */ +public class MutableShort extends Number implements Comparable, Mutable { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = -2135791679L; + + /** The mutable value. */ + private short value; + + /** + * Constructs a new MutableShort with the default value of zero. + */ + public MutableShort() { + super(); + } + + /** + * Constructs a new MutableShort with the specified value. + * + * @param value the initial value to store + */ + public MutableShort(final short value) { + super(); + this.value = value; + } + + /** + * Constructs a new MutableShort with the specified value. + * + * @param value the initial value to store, not null + * @throws NullPointerException if the object is null + */ + public MutableShort(final Number value) { + super(); + this.value = value.shortValue(); + } + + /** + * Constructs a new MutableShort parsing the given string. + * + * @param value the string to parse, not null + * @throws NumberFormatException if the string cannot be parsed into a short + * @since 2.5 + */ + public MutableShort(final String value) throws NumberFormatException { + super(); + this.value = Short.parseShort(value); + } + + //----------------------------------------------------------------------- + /** + * Gets the value as a Short instance. + * + * @return the value as a Short, never null + */ + @Override + public Short getValue() { + return Short.valueOf(this.value); + } + + /** + * Sets the value. + * + * @param value the value to set + */ + public void setValue(final short value) { + this.value = value; + } + + /** + * Sets the value from any Number instance. + * + * @param value the value to set, not null + * @throws NullPointerException if the object is null + */ + @Override + public void setValue(final Number value) { + this.value = value.shortValue(); + } + + //----------------------------------------------------------------------- + /** + * Increments the value. + * + * @since Commons Lang 2.2 + */ + public void increment() { + value++; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the increment operation. This method is not thread safe. + * + * @return the value associated with the instance before it was incremented + * @since 3.5 + */ + public short getAndIncrement() { + final short last = value; + value++; + return last; + } + + /** + * Increments this instance's value by 1; this method returns the value associated with the instance + * immediately after the increment operation. This method is not thread safe. + * + * @return the value associated with the instance after it is incremented + * @since 3.5 + */ + public short incrementAndGet() { + value++; + return value; + } + + /** + * Decrements the value. + * + * @since Commons Lang 2.2 + */ + public void decrement() { + value--; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately prior to the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance before it was decremented + * @since 3.5 + */ + public short getAndDecrement() { + final short last = value; + value--; + return last; + } + + /** + * Decrements this instance's value by 1; this method returns the value associated with the instance + * immediately after the decrement operation. This method is not thread safe. + * + * @return the value associated with the instance after it is decremented + * @since 3.5 + */ + public short decrementAndGet() { + value--; + return value; + } + + //----------------------------------------------------------------------- + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @since Commons Lang 2.2 + */ + public void add(final short operand) { + this.value += operand; + } + + /** + * Adds a value to the value of this instance. + * + * @param operand the value to add, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void add(final Number operand) { + this.value += operand.shortValue(); + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @since Commons Lang 2.2 + */ + public void subtract(final short operand) { + this.value -= operand; + } + + /** + * Subtracts a value from the value of this instance. + * + * @param operand the value to subtract, not null + * @throws NullPointerException if the object is null + * @since Commons Lang 2.2 + */ + public void subtract(final Number operand) { + this.value -= operand.shortValue(); + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public short addAndGet(final short operand) { + this.value += operand; + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately after the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance after adding the operand + * @since 3.5 + */ + public short addAndGet(final Number operand) { + this.value += operand.shortValue(); + return value; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public short getAndAdd(final short operand) { + final short last = value; + this.value += operand; + return last; + } + + /** + * Increments this instance's value by {@code operand}; this method returns the value associated with the instance + * immediately prior to the addition operation. This method is not thread safe. + * + * @param operand the quantity to add, not null + * @throws NullPointerException if {@code operand} is null + * @return the value associated with this instance immediately before the operand was added + * @since 3.5 + */ + public short getAndAdd(final Number operand) { + final short last = value; + this.value += operand.shortValue(); + return last; + } + + //----------------------------------------------------------------------- + // byteValue relies on Number implementation + /** + * Returns the value of this MutableShort as a short. + * + * @return the numeric value represented by this object after conversion to type short. + */ + @Override + public short shortValue() { + return value; + } + + /** + * Returns the value of this MutableShort as an int. + * + * @return the numeric value represented by this object after conversion to type int. + */ + @Override + public int intValue() { + return value; + } + + /** + * Returns the value of this MutableShort as a long. + * + * @return the numeric value represented by this object after conversion to type long. + */ + @Override + public long longValue() { + return value; + } + + /** + * Returns the value of this MutableShort as a float. + * + * @return the numeric value represented by this object after conversion to type float. + */ + @Override + public float floatValue() { + return value; + } + + /** + * Returns the value of this MutableShort as a double. + * + * @return the numeric value represented by this object after conversion to type double. + */ + @Override + public double doubleValue() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Gets this mutable as an instance of Short. + * + * @return a Short instance containing the value from this mutable, never null + */ + public Short toShort() { + return Short.valueOf(shortValue()); + } + + //----------------------------------------------------------------------- + /** + * Compares this object to the specified object. The result is true if and only if the argument + * is not null and is a MutableShort object that contains the same short + * value as this object. + * + * @param obj the object to compare with, null returns false + * @return true if the objects are the same; false otherwise. + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof MutableShort) { + return value == ((MutableShort) obj).shortValue(); + } + return false; + } + + /** + * Returns a suitable hash code for this mutable. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return value; + } + + //----------------------------------------------------------------------- + /** + * Compares this mutable to another in ascending order. + * + * @param other the other mutable to compare to, not null + * @return negative if this is less, zero if equal, positive if greater + */ + @Override + public int compareTo(final MutableShort other) { + return NumberUtils.compare(this.value, other.value); + } + + //----------------------------------------------------------------------- + /** + * Returns the String value of this mutable. + * + * @return the mutable value as a string + */ + @Override + public String toString() { + return String.valueOf(value); + } + +} diff --git a/src/org/apache/commons/lang3/mutable/package-info.java b/src/org/apache/commons/lang3/mutable/package-info.java new file mode 100644 index 0000000..c5b8347 --- /dev/null +++ b/src/org/apache/commons/lang3/mutable/package-info.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Provides typed mutable wrappers to primitive values and Object. + * These wrappers are similar to the wrappers provided by the Java API, but allow the wrapped value to be changed without needing to create a separate wrapper object. + * These classes are not thread-safe.

              + * + * @since 2.1 + */ +package org.apache.commons.lang3.mutable; diff --git a/src/org/apache/commons/lang3/package-info.java b/src/org/apache/commons/lang3/package-info.java new file mode 100644 index 0000000..88779d7 --- /dev/null +++ b/src/org/apache/commons/lang3/package-info.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Provides highly reusable static utility methods, chiefly concerned with adding value to the {@link java.lang} classes. + * Most of these classes are immutable and thus thread-safe. + * However {@link org.apache.commons.lang3.CharSet} is not currently guaranteed thread-safe under all circumstances.

              + * + *

              The top level package contains various Utils classes, whilst there are various subpackages including {@link org.apache.commons.lang3.math}, {@link org.apache.commons.lang3.concurrent} and {@link org.apache.commons.lang3.builder}. + * Using the Utils classes is generally simplicity itself. + * They are the equivalent of global functions in another language, a collection of stand-alone, thread-safe, static methods. + * In contrast, subpackages may contain interfaces which may have to be implemented or classes which may need to be extended to get the full functionality from the code. + * They may, however, contain more global-like functions.

              + * + *

              Lang 3.0 requires JDK 1.5+, since Lang 3.2 it requires JDK 6+; The legacy release 2.6 requires JDK 1.2+. + * In both cases you can find features of later JDKs being maintained by us and likely to be removed or modified in favour of the JDK in the next major version. + * Note that Lang 3.0 uses a different package than its predecessors, allowing it to be used at the same time as an earlier version.

              + * + *

              You will find deprecated methods as you stroll through the Lang documentation. These are removed in the next major version.

              + * + *

              All util classes contain empty public constructors with warnings not to use. + * This may seem an odd thing to do, but it allows tools like Velocity to access the class as if it were a bean. + * In other words, yes we know about private constructors and have chosen not to use them.

              + * + *

              String manipulation - StringUtils, StringEscapeUtils, RandomStringUtils

              + * + *

              Lang has a series of String utilities. + * The first is {@link org.apache.commons.lang3.StringUtils}, oodles and oodles of functions which tweak, transform, squeeze and cuddle {@link java.lang.String java.lang.Strings}. + * In addition to StringUtils, there are a series of other String manipulating classes; {@link org.apache.commons.lang3.RandomStringUtils} and {@link org.apache.commons.lang3.StringEscapeUtils StringEscapeUtils}. + * RandomStringUtils speaks for itself. + * It's provides ways in which to generate pieces of text, such as might be used for default passwords. + * StringEscapeUtils contains methods to escape and unescape Java, JavaScript, HTML, XML and SQL.

              + * + *

              These are ideal classes to start using if you're looking to get into Lang. + * StringUtils' {@link org.apache.commons.lang3.StringUtils#capitalize(String)}, {@link org.apache.commons.lang3.StringUtils#substringBetween(String, String)}/{@link org.apache.commons.lang3.StringUtils#substringBefore(String, String) Before}/{@link org.apache.commons.lang3.StringUtils#substringAfter(String, String) After}, {@link org.apache.commons.lang3.StringUtils#split(String)} and {@link org.apache.commons.lang3.StringUtils#join(Object[])} are good methods to begin with. + * If you use java.sql.Statements a lot, StringEscapeUtils.escapeSql might be of interest.

              + * + *

              Character handling - CharSetUtils, CharSet, CharRange, CharUtils

              + * + *

              In addition to dealing with Strings, it's also important to deal with chars and Characters. + * {@link org.apache.commons.lang3.CharUtils} exists for this purpose, while {@link org.apache.commons.lang3.CharSetUtils} exists for set-manipulation of Strings. + * Be careful, although CharSetUtils takes an argument of type String, it is only as a set of characters. + * For example, CharSetUtils.delete("testtest", "tr") will remove all t's and all r's from the String, not just the String "tr".

              + * + *

              {@link org.apache.commons.lang3.CharRange} and {@link org.apache.commons.lang3.CharSet} are both used internally by CharSetUtils, and will probably rarely be used.

              + * + *

              JVM interaction - SystemUtils, CharEncoding

              + * + *

              SystemUtils is a simple little class which makes it easy to find out information about which platform you are on. + * For some, this is a necessary evil. It was never something I expected to use myself until I was trying to ensure that Commons Lang itself compiled under JDK 1.2. + * Having pushed out a few JDK 1.3 bits that had slipped in (Collections.EMPTY_MAP is a classic offender), I then found that one of the Unit Tests was dying mysteriously under JDK 1.2, but ran fine under JDK 1.3. + * There was no obvious solution and I needed to move onwards, so the simple solution was to wrap that particular test in a if(SystemUtils.isJavaVersionAtLeast(1.3f)) {, make a note and move on.

              + * + *

              The {@link org.apache.commons.lang3.CharEncoding} class is also used to interact with the Java environment and may be used to see which character encodings are supported in a particular environment.

              + * + *

              Serialization - SerializationUtils, SerializationException

              + * + *

              Serialization doesn't have to be that hard! + * A simple util class can take away the pain, plus it provides a method to clone an object by unserializing and reserializing, an old Java trick.

              + * + *

              Assorted functions - ObjectUtils, ClassUtils, ArrayUtils, BooleanUtils

              + * + *

              Would you believe it, {@link org.apache.commons.lang3.ObjectUtils} contains handy functions for Objects, mainly null-safe implementations of the methods on {@link java.lang.Object}.

              + * + *

              {@link org.apache.commons.lang3.ClassUtils} is largely a set of helper methods for reflection. + * Of special note are the comparators hidden away in ClassUtils, useful for sorting Class and Package objects by name; however they merely sort alphabetically and don't understand the common habit of sorting java and javax first.

              + * + *

              Next up, {@link org.apache.commons.lang3.ArrayUtils}. + * This is a big one with many methods and many overloads of these methods so it is probably worth an in depth look here. + * Before we begin, assume that every method mentioned is overloaded for all the primitives and for Object. + * Also, the short-hand 'xxx' implies a generic primitive type, but usually also includes Object.

              + * + *
                + *
              • ArrayUtils provides singleton empty arrays for all the basic types. These will largely be of use in the Collections API with its toArray methods, but also will be of use with methods which want to return an empty array on error.
              • + *
              • add(xxx[], xxx) will add a primitive type to an array, resizing the array as you'd expect. Object is also supported.
              • + *
              • clone(xxx[]) clones a primitive or Object array.
              • + *
              • contains(xxx[], xxx) searches for a primitive or Object in a primitive or Object array.
              • + *
              • getLength(Object) returns the length of any array or an IllegalArgumentException if the parameter is not an array. hashCode(Object), equals(Object, Object), toString(Object)
              • + *
              • indexOf(xxx[], xxx) and indexOf(xxx[], xxx, int) are copies of the classic String methods, but this time for primitive/Object arrays. In addition, a lastIndexOf set of methods exists.
              • + *
              • isEmpty(xxx[]) lets you know if an array is zero-sized or null.
              • + *
              • isSameLength(xxx[], xxx[]) returns true if the arrays are the same length.
              • + *
              • Along side the add methods, there are also remove methods of two types. The first type remove the value at an index, remove(xxx[], int), while the second type remove the first value from the array, remove(xxx[], xxx).
              • + *
              • Nearing the end now. The reverse(xxx[]) method turns an array around.
              • + *
              • The subarray(xxx[], int, int) method splices an array out of a larger array.
              • + *
              • Primitive to primitive wrapper conversion is handled by the toObject(xxx[]) and toPrimitive(Xxx[]) methods.
              • + *
              + * + *

              Lastly, {@link org.apache.commons.lang3.ArrayUtils#toMap(Object[])} is worthy of special note. + * It is not a heavily overloaded method for working with arrays, but a simple way to create Maps from literals.

              + * + *

              Using toMap

              + *
              + * 
              + * Map colorMap = ArrayUtils.toMap(new String[][] {{
              + *   {"RED", "#FF0000"},
              + *   {"GREEN", "#00FF00"},
              + *   {"BLUE", "#0000FF"}
              + * });
              + * 
              + * 
              + * + *

              Our final util class is {@link org.apache.commons.lang3.BooleanUtils}. + * It contains various Boolean acting methods, probably of most interest is the {@link org.apache.commons.lang3.BooleanUtils#toBoolean(String)} method which turns various positive/negative Strings into a Boolean object, and not just true/false as with Boolean.valueOf.

              + * + *

              Flotsam - BitField, Validate

              + *

              On reaching the end of our package, we are left with a couple of classes that haven't fit any of the topics so far.

              + *

              The {@link org.apache.commons.lang3.BitField} class provides a wrapper class around the classic bitmask integer, whilst the {@link org.apache.commons.lang3.Validate} class may be used for assertions (remember, we support Java 1.2).

              + * + * @since 1.0 + */ +package org.apache.commons.lang3; diff --git a/src/org/apache/commons/lang3/reflect/ConstructorUtils.java b/src/org/apache/commons/lang3/reflect/ConstructorUtils.java new file mode 100644 index 0000000..0808fc7 --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/ConstructorUtils.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.Validate; + +/** + *

              Utility reflection methods focused on constructors, modeled after + * {@link MethodUtils}.

              + * + *

              Known Limitations

              Accessing Public Constructors In A Default + * Access Superclass

              There is an issue when invoking {@code public} constructors + * contained in a default access superclass. Reflection correctly locates these + * constructors and assigns them as {@code public}. However, an + * {@link IllegalAccessException} is thrown if the constructor is + * invoked.

              + * + *

              {@link ConstructorUtils} contains a workaround for this situation: it + * will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this constructor. If this + * call succeeds, then the method can be invoked as normal. This call will only + * succeed when the application has sufficient security privileges. If this call + * fails then a warning will be logged and the method may fail.

              + * + * @since 2.5 + */ +public class ConstructorUtils { + + /** + *

              ConstructorUtils instances should NOT be constructed in standard + * programming. Instead, the class should be used as + * {@code ConstructorUtils.invokeConstructor(cls, args)}.

              + * + *

              This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

              + */ + public ConstructorUtils() { + super(); + } + + /** + *

              Returns a new instance of the specified class inferring the right constructor + * from the types of the arguments.

              + * + *

              This locates and calls a constructor. + * The constructor signature must match the argument types by assignment compatibility.

              + * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @return new instance of {@code cls}, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[]) + */ + public static T invokeConstructor(final Class cls, Object... args) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + args = ArrayUtils.nullToEmpty(args); + final Class parameterTypes[] = ClassUtils.toClass(args); + return invokeConstructor(cls, args, parameterTypes); + } + + /** + *

              Returns a new instance of the specified class choosing the right constructor + * from the list of parameter types.

              + * + *

              This locates and calls a constructor. + * The constructor signature must match the parameter types by assignment compatibility.

              + * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @param parameterTypes the array of parameter types, {@code null} treated as empty + * @return new instance of {@code cls}, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see Constructor#newInstance + */ + public static T invokeConstructor(final Class cls, Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Constructor ctor = getMatchingAccessibleConstructor(cls, parameterTypes); + if (ctor == null) { + throw new NoSuchMethodException( + "No such accessible constructor on object: " + cls.getName()); + } + if (ctor.isVarArgs()) { + final Class[] methodParameterTypes = ctor.getParameterTypes(); + args = MethodUtils.getVarArgs(args, methodParameterTypes); + } + return ctor.newInstance(args); + } + + /** + *

              Returns a new instance of the specified class inferring the right constructor + * from the types of the arguments.

              + * + *

              This locates and calls a constructor. + * The constructor signature must match the argument types exactly.

              + * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @return new instance of {@code cls}, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[]) + */ + public static T invokeExactConstructor(final Class cls, Object... args) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + args = ArrayUtils.nullToEmpty(args); + final Class parameterTypes[] = ClassUtils.toClass(args); + return invokeExactConstructor(cls, args, parameterTypes); + } + + /** + *

              Returns a new instance of the specified class choosing the right constructor + * from the list of parameter types.

              + * + *

              This locates and calls a constructor. + * The constructor signature must match the parameter types exactly.

              + * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @param parameterTypes the array of parameter types, {@code null} treated as empty + * @return new instance of cls, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see Constructor#newInstance + */ + public static T invokeExactConstructor(final Class cls, Object[] args, + Class[] parameterTypes) throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException, InstantiationException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Constructor ctor = getAccessibleConstructor(cls, parameterTypes); + if (ctor == null) { + throw new NoSuchMethodException( + "No such accessible constructor on object: "+ cls.getName()); + } + return ctor.newInstance(args); + } + + //----------------------------------------------------------------------- + /** + *

              Finds a constructor given a class and signature, checking accessibility.

              + * + *

              This finds the constructor and ensures that it is accessible. + * The constructor signature must match the parameter types exactly.

              + * + * @param the constructor type + * @param cls the class to find a constructor for, not {@code null} + * @param parameterTypes the array of parameter types, {@code null} treated as empty + * @return the constructor, {@code null} if no matching accessible constructor found + * @see Class#getConstructor + * @see #getAccessibleConstructor(java.lang.reflect.Constructor) + * @throws NullPointerException if {@code cls} is {@code null} + */ + public static Constructor getAccessibleConstructor(final Class cls, + final Class... parameterTypes) { + Validate.notNull(cls, "class cannot be null"); + try { + return getAccessibleConstructor(cls.getConstructor(parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

              Checks if the specified constructor is accessible.

              + * + *

              This simply ensures that the constructor is accessible.

              + * + * @param the constructor type + * @param ctor the prototype constructor object, not {@code null} + * @return the constructor, {@code null} if no matching accessible constructor found + * @see java.lang.SecurityManager + * @throws NullPointerException if {@code ctor} is {@code null} + */ + public static Constructor getAccessibleConstructor(final Constructor ctor) { + Validate.notNull(ctor, "constructor cannot be null"); + return MemberUtils.isAccessible(ctor) + && isAccessible(ctor.getDeclaringClass()) ? ctor : null; + } + + /** + *

              Finds an accessible constructor with compatible parameters.

              + * + *

              This checks all the constructor and finds one with compatible parameters + * This requires that every parameter is assignable from the given parameter types. + * This is a more flexible search than the normal exact matching algorithm.

              + * + *

              First it checks if there is a constructor matching the exact signature. + * If not then all the constructors of the class are checked to see if their + * signatures are assignment-compatible with the parameter types. + * The first assignment-compatible matching constructor is returned.

              + * + * @param the constructor type + * @param cls the class to find a constructor for, not {@code null} + * @param parameterTypes find method with compatible parameters + * @return the constructor, null if no matching accessible constructor found + * @throws NullPointerException if {@code cls} is {@code null} + */ + public static Constructor getMatchingAccessibleConstructor(final Class cls, + final Class... parameterTypes) { + Validate.notNull(cls, "class cannot be null"); + // see if we can find the constructor directly + // most of the time this works and it's much faster + try { + final Constructor ctor = cls.getConstructor(parameterTypes); + MemberUtils.setAccessibleWorkaround(ctor); + return ctor; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow + } + Constructor result = null; + /* + * (1) Class.getConstructors() is documented to return Constructor so as + * long as the array is not subsequently modified, everything's fine. + */ + final Constructor[] ctors = cls.getConstructors(); + + // return best match: + for (Constructor ctor : ctors) { + // compare parameters + if (MemberUtils.isMatchingConstructor(ctor, parameterTypes)) { + // get accessible version of constructor + ctor = getAccessibleConstructor(ctor); + if (ctor != null) { + MemberUtils.setAccessibleWorkaround(ctor); + if (result == null || MemberUtils.compareConstructorFit(ctor, result, parameterTypes) < 0) { + // temporary variable for annotation, see comment above (1) + @SuppressWarnings("unchecked") + final + Constructor constructor = (Constructor)ctor; + result = constructor; + } + } + } + } + return result; + } + + /** + * Learn whether the specified class is generally accessible, i.e. is + * declared in an entirely {@code public} manner. + * @param type to check + * @return {@code true} if {@code type} and any enclosing classes are + * {@code public}. + */ + private static boolean isAccessible(final Class type) { + Class cls = type; + while (cls != null) { + if (!Modifier.isPublic(cls.getModifiers())) { + return false; + } + cls = cls.getEnclosingClass(); + } + return true; + } + +} diff --git a/src/org/apache/commons/lang3/reflect/FieldUtils.java b/src/org/apache/commons/lang3/reflect/FieldUtils.java new file mode 100644 index 0000000..494c3de --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/FieldUtils.java @@ -0,0 +1,839 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; + +/** + * Utilities for working with {@link Field}s by reflection. Adapted and refactored from the dormant [reflect] Commons + * sandbox component. + *

              + * The ability is provided to break the scoping restrictions coded by the programmer. This can allow fields to be + * changed that shouldn't be. This facility should be used with care. + * + * @since 2.5 + */ +public class FieldUtils { + + /** + * {@link FieldUtils} instances should NOT be constructed in standard programming. + *

              + * This constructor is {@code public} to permit tools that require a JavaBean instance to operate. + *

              + */ + public FieldUtils() { + super(); + } + + /** + * Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @return the Field object + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty + */ + public static Field getField(final Class cls, final String fieldName) { + final Field field = getField(cls, fieldName, false); + MemberUtils.setAccessibleWorkaround(field); + return field; + } + + /** + * Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be + * considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @return the Field object + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty or is matched at multiple places + * in the inheritance hierarchy + */ + public static Field getField(final Class cls, final String fieldName, final boolean forceAccess) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty"); + // FIXME is this workaround still needed? lang requires Java 6 + // Sun Java 1.3 has a bugged implementation of getField hence we write the + // code ourselves + + // getField() will return the Field object with the declaring class + // set correctly to the class that declares the field. Thus requesting the + // field on a subclass will return the field from the superclass. + // + // priority order for lookup: + // searchclass private/protected/package/public + // superclass protected/package/public + // private/different package blocks access to further superclasses + // implementedinterface public + + // check up the superclass hierarchy + for (Class acls = cls; acls != null; acls = acls.getSuperclass()) { + try { + final Field field = acls.getDeclaredField(fieldName); + // getDeclaredField checks for non-public scopes as well + // and it returns accurate results + if (!Modifier.isPublic(field.getModifiers())) { + if (forceAccess) { + field.setAccessible(true); + } else { + continue; + } + } + return field; + } catch (final NoSuchFieldException ex) { // NOPMD + // ignore + } + } + // check the public interface case. This must be manually searched for + // incase there is a public supersuperclass field hidden by a private/package + // superclass field. + Field match = null; + for (final Class class1 : ClassUtils.getAllInterfaces(cls)) { + try { + final Field test = class1.getField(fieldName); + Validate.isTrue(match == null, "Reference to field %s is ambiguous relative to %s" + + "; a matching field exists on two or more implemented interfaces.", fieldName, cls); + match = test; + } catch (final NoSuchFieldException ex) { // NOPMD + // ignore + } + } + return match; + } + + /** + * Gets an accessible {@link Field} by name respecting scope. Only the specified class will be considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @return the Field object + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty + */ + public static Field getDeclaredField(final Class cls, final String fieldName) { + return getDeclaredField(cls, fieldName, false); + } + + /** + * Gets an accessible {@link Field} by name, breaking scope if requested. Only the specified class will be + * considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @return the Field object + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty + */ + public static Field getDeclaredField(final Class cls, final String fieldName, final boolean forceAccess) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty"); + try { + // only consider the specified class by using getDeclaredField() + final Field field = cls.getDeclaredField(fieldName); + if (!MemberUtils.isAccessible(field)) { + if (forceAccess) { + field.setAccessible(true); + } else { + return null; + } + } + return field; + } catch (final NoSuchFieldException e) { // NOPMD + // ignore + } + return null; + } + + /** + * Gets all fields of the given class and its parents (if any). + * + * @param cls + * the {@link Class} to query + * @return an array of Fields (possibly empty). + * @throws IllegalArgumentException + * if the class is {@code null} + * @since 3.2 + */ + public static Field[] getAllFields(final Class cls) { + final List allFieldsList = getAllFieldsList(cls); + return allFieldsList.toArray(new Field[allFieldsList.size()]); + } + + /** + * Gets all fields of the given class and its parents (if any). + * + * @param cls + * the {@link Class} to query + * @return an array of Fields (possibly empty). + * @throws IllegalArgumentException + * if the class is {@code null} + * @since 3.2 + */ + public static List getAllFieldsList(final Class cls) { + Validate.isTrue(cls != null, "The class must not be null"); + final List allFields = new ArrayList<>(); + Class currentClass = cls; + while (currentClass != null) { + final Field[] declaredFields = currentClass.getDeclaredFields(); + for (final Field field : declaredFields) { + allFields.add(field); + } + currentClass = currentClass.getSuperclass(); + } + return allFields; + } + + /** + * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a field to be matched + * @return an array of Fields (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Field[] getFieldsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedFieldsList = getFieldsListWithAnnotation(cls, annotationCls); + return annotatedFieldsList.toArray(new Field[annotatedFieldsList.size()]); + } + + /** + * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a field to be matched + * @return a list of Fields (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getFieldsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final List allFields = getAllFieldsList(cls); + final List annotatedFields = new ArrayList<>(); + for (final Field field : allFields) { + if (field.getAnnotation(annotationCls) != null) { + annotatedFields.add(field); + } + } + return annotatedFields; + } + + /** + * Reads an accessible {@code static} {@link Field}. + * + * @param field + * to read + * @return the field value + * @throws IllegalArgumentException + * if the field is {@code null}, or not {@code static} + * @throws IllegalAccessException + * if the field is not accessible + */ + public static Object readStaticField(final Field field) throws IllegalAccessException { + return readStaticField(field, false); + } + + /** + * Reads a static {@link Field}. + * + * @param field + * to read + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. + * @return the field value + * @throws IllegalArgumentException + * if the field is {@code null} or not {@code static} + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static Object readStaticField(final Field field, final boolean forceAccess) throws IllegalAccessException { + Validate.isTrue(field != null, "The field must not be null"); + Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field '%s' is not static", field.getName()); + return readField(field, (Object) null, forceAccess); + } + + /** + * Reads the named {@code public static} {@link Field}. Superclasses will be considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @return the value of the field + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could + * not be found + * @throws IllegalAccessException + * if the field is not accessible + */ + public static Object readStaticField(final Class cls, final String fieldName) throws IllegalAccessException { + return readStaticField(cls, fieldName, false); + } + + /** + * Reads the named {@code static} {@link Field}. Superclasses will be considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @return the Field object + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could + * not be found + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static Object readStaticField(final Class cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException { + final Field field = getField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate field '%s' on %s", fieldName, cls); + // already forced access above, don't repeat it here: + return readStaticField(field, false); + } + + /** + * Gets the value of a {@code static} {@link Field} by name. The field must be {@code public}. Only the specified + * class will be considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @return the value of the field + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could + * not be found + * @throws IllegalAccessException + * if the field is not accessible + */ + public static Object readDeclaredStaticField(final Class cls, final String fieldName) throws IllegalAccessException { + return readDeclaredStaticField(cls, fieldName, false); + } + + /** + * Gets the value of a {@code static} {@link Field} by name. Only the specified class will be considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @return the Field object + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty, is not {@code static}, or could + * not be found + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static Object readDeclaredStaticField(final Class cls, final String fieldName, final boolean forceAccess) throws IllegalAccessException { + final Field field = getDeclaredField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName); + // already forced access above, don't repeat it here: + return readStaticField(field, false); + } + + /** + * Reads an accessible {@link Field}. + * + * @param field + * the field to use + * @param target + * the object to call on, may be {@code null} for {@code static} fields + * @return the field value + * @throws IllegalArgumentException + * if the field is {@code null} + * @throws IllegalAccessException + * if the field is not accessible + */ + public static Object readField(final Field field, final Object target) throws IllegalAccessException { + return readField(field, target, false); + } + + /** + * Reads a {@link Field}. + * + * @param field + * the field to use + * @param target + * the object to call on, may be {@code null} for {@code static} fields + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. + * @return the field value + * @throws IllegalArgumentException + * if the field is {@code null} + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static Object readField(final Field field, final Object target, final boolean forceAccess) throws IllegalAccessException { + Validate.isTrue(field != null, "The field must not be null"); + if (forceAccess && !field.isAccessible()) { + field.setAccessible(true); + } else { + MemberUtils.setAccessibleWorkaround(field); + } + return field.get(target); + } + + /** + * Reads the named {@code public} {@link Field}. Superclasses will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @return the value of the field + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty or could not be found + * @throws IllegalAccessException + * if the named field is not {@code public} + */ + public static Object readField(final Object target, final String fieldName) throws IllegalAccessException { + return readField(target, fieldName, false); + } + + /** + * Reads the named {@link Field}. Superclasses will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @return the field value + * @throws IllegalArgumentException + * if {@code target} is {@code null}, or the field name is blank or empty or could not be found + * @throws IllegalAccessException + * if the named field is not made accessible + */ + public static Object readField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException { + Validate.isTrue(target != null, "target object must not be null"); + final Class cls = target.getClass(); + final Field field = getField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls); + // already forced access above, don't repeat it here: + return readField(field, target, false); + } + + /** + * Reads the named {@code public} {@link Field}. Only the class of the specified object will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @return the value of the field + * @throws IllegalArgumentException + * if {@code target} is {@code null}, or the field name is blank or empty or could not be found + * @throws IllegalAccessException + * if the named field is not {@code public} + */ + public static Object readDeclaredField(final Object target, final String fieldName) throws IllegalAccessException { + return readDeclaredField(target, fieldName, false); + } + + /** + * Gets a {@link Field} value by name. Only the class of the specified object will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match public fields. + * @return the Field object + * @throws IllegalArgumentException + * if {@code target} is {@code null}, or the field name is blank or empty or could not be found + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static Object readDeclaredField(final Object target, final String fieldName, final boolean forceAccess) throws IllegalAccessException { + Validate.isTrue(target != null, "target object must not be null"); + final Class cls = target.getClass(); + final Field field = getDeclaredField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls, fieldName); + // already forced access above, don't repeat it here: + return readField(field, target, false); + } + + /** + * Writes a {@code public static} {@link Field}. + * + * @param field + * to write + * @param value + * to set + * @throws IllegalArgumentException + * if the field is {@code null} or not {@code static}, or {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not {@code public} or is {@code final} + */ + public static void writeStaticField(final Field field, final Object value) throws IllegalAccessException { + writeStaticField(field, value, false); + } + + /** + * Writes a static {@link Field}. + * + * @param field + * to write + * @param value + * to set + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @throws IllegalArgumentException + * if the field is {@code null} or not {@code static}, or {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not made accessible or is {@code final} + */ + public static void writeStaticField(final Field field, final Object value, final boolean forceAccess) throws IllegalAccessException { + Validate.isTrue(field != null, "The field must not be null"); + Validate.isTrue(Modifier.isStatic(field.getModifiers()), "The field %s.%s is not static", field.getDeclaringClass().getName(), + field.getName()); + writeField(field, (Object) null, value, forceAccess); + } + + /** + * Writes a named {@code public static} {@link Field}. Superclasses will be considered. + * + * @param cls + * {@link Class} on which the field is to be found + * @param fieldName + * to write + * @param value + * to set + * @throws IllegalArgumentException + * if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is + * not {@code static}, or {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not {@code public} or is {@code final} + */ + public static void writeStaticField(final Class cls, final String fieldName, final Object value) throws IllegalAccessException { + writeStaticField(cls, fieldName, value, false); + } + + /** + * Writes a named {@code static} {@link Field}. Superclasses will be considered. + * + * @param cls + * {@link Class} on which the field is to be found + * @param fieldName + * to write + * @param value + * to set + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @throws IllegalArgumentException + * if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is + * not {@code static}, or {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not made accessible or is {@code final} + */ + public static void writeStaticField(final Class cls, final String fieldName, final Object value, final boolean forceAccess) + throws IllegalAccessException { + final Field field = getField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate field %s on %s", fieldName, cls); + // already forced access above, don't repeat it here: + writeStaticField(field, value, false); + } + + /** + * Writes a named {@code public static} {@link Field}. Only the specified class will be considered. + * + * @param cls + * {@link Class} on which the field is to be found + * @param fieldName + * to write + * @param value + * to set + * @throws IllegalArgumentException + * if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is + * not {@code static}, or {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not {@code public} or is {@code final} + */ + public static void writeDeclaredStaticField(final Class cls, final String fieldName, final Object value) throws IllegalAccessException { + writeDeclaredStaticField(cls, fieldName, value, false); + } + + /** + * Writes a named {@code static} {@link Field}. Only the specified class will be considered. + * + * @param cls + * {@link Class} on which the field is to be found + * @param fieldName + * to write + * @param value + * to set + * @param forceAccess + * whether to break scope restrictions using the {@code AccessibleObject#setAccessible(boolean)} method. + * {@code false} will only match {@code public} fields. + * @throws IllegalArgumentException + * if {@code cls} is {@code null}, the field name is blank or empty, the field cannot be located or is + * not {@code static}, or {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not made accessible or is {@code final} + */ + public static void writeDeclaredStaticField(final Class cls, final String fieldName, final Object value, final boolean forceAccess) + throws IllegalAccessException { + final Field field = getDeclaredField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName); + // already forced access above, don't repeat it here: + writeField(field, (Object) null, value, false); + } + + /** + * Writes an accessible {@link Field}. + * + * @param field + * to write + * @param target + * the object to call on, may be {@code null} for {@code static} fields + * @param value + * to set + * @throws IllegalAccessException + * if the field or target is {@code null}, the field is not accessible or is {@code final}, or + * {@code value} is not assignable + */ + public static void writeField(final Field field, final Object target, final Object value) throws IllegalAccessException { + writeField(field, target, value, false); + } + + /** + * Writes a {@link Field}. + * + * @param field + * to write + * @param target + * the object to call on, may be {@code null} for {@code static} fields + * @param value + * to set + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @throws IllegalArgumentException + * if the field is {@code null} or {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not made accessible or is {@code final} + */ + public static void writeField(final Field field, final Object target, final Object value, final boolean forceAccess) + throws IllegalAccessException { + Validate.isTrue(field != null, "The field must not be null"); + if (forceAccess && !field.isAccessible()) { + field.setAccessible(true); + } else { + MemberUtils.setAccessibleWorkaround(field); + } + field.set(target, value); + } + + /** + * Removes the final modifier from a {@link Field}. + * + * @param field + * to remove the final modifier + * @throws IllegalArgumentException + * if the field is {@code null} + * @since 3.2 + */ + public static void removeFinalModifier(final Field field) { + removeFinalModifier(field, true); + } + + /** + * Removes the final modifier from a {@link Field}. + * + * @param field + * to remove the final modifier + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @throws IllegalArgumentException + * if the field is {@code null} + * @since 3.3 + */ + public static void removeFinalModifier(final Field field, final boolean forceAccess) { + Validate.isTrue(field != null, "The field must not be null"); + + try { + if (Modifier.isFinal(field.getModifiers())) { + // Do all JREs implement Field with a private ivar called "modifiers"? + final Field modifiersField = Field.class.getDeclaredField("modifiers"); + final boolean doForceAccess = forceAccess && !modifiersField.isAccessible(); + if (doForceAccess) { + modifiersField.setAccessible(true); + } + try { + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + } finally { + if (doForceAccess) { + modifiersField.setAccessible(false); + } + } + } + } catch (final NoSuchFieldException ignored) { + // The field class contains always a modifiers field + } catch (final IllegalAccessException ignored) { + // The modifiers field is made accessible + } + } + + /** + * Writes a {@code public} {@link Field}. Superclasses will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param value + * to set + * @throws IllegalArgumentException + * if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or + * {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not accessible + */ + public static void writeField(final Object target, final String fieldName, final Object value) throws IllegalAccessException { + writeField(target, fieldName, value, false); + } + + /** + * Writes a {@link Field}. Superclasses will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param value + * to set + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @throws IllegalArgumentException + * if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or + * {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static void writeField(final Object target, final String fieldName, final Object value, final boolean forceAccess) + throws IllegalAccessException { + Validate.isTrue(target != null, "target object must not be null"); + final Class cls = target.getClass(); + final Field field = getField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName); + // already forced access above, don't repeat it here: + writeField(field, target, value, false); + } + + /** + * Writes a {@code public} {@link Field}. Only the specified class will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param value + * to set + * @throws IllegalArgumentException + * if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or + * {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static void writeDeclaredField(final Object target, final String fieldName, final Object value) throws IllegalAccessException { + writeDeclaredField(target, fieldName, value, false); + } + + /** + * Writes a {@code public} {@link Field}. Only the specified class will be considered. + * + * @param target + * the object to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param value + * to set + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @throws IllegalArgumentException + * if {@code target} is {@code null}, {@code fieldName} is blank or empty or could not be found, or + * {@code value} is not assignable + * @throws IllegalAccessException + * if the field is not made accessible + */ + public static void writeDeclaredField(final Object target, final String fieldName, final Object value, final boolean forceAccess) + throws IllegalAccessException { + Validate.isTrue(target != null, "target object must not be null"); + final Class cls = target.getClass(); + final Field field = getDeclaredField(cls, fieldName, forceAccess); + Validate.isTrue(field != null, "Cannot locate declared field %s.%s", cls.getName(), fieldName); + // already forced access above, don't repeat it here: + writeField(field, target, value, false); + } +} diff --git a/src/org/apache/commons/lang3/reflect/InheritanceUtils.java b/src/org/apache/commons/lang3/reflect/InheritanceUtils.java new file mode 100644 index 0000000..4f97f98 --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/InheritanceUtils.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import org.apache.commons.lang3.BooleanUtils; + +/** + *

              Utility methods focusing on inheritance.

              + * + * @since 3.2 + */ +public class InheritanceUtils { + + /** + *

              {@link InheritanceUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

              + * + *

              This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

              + */ + public InheritanceUtils() { + super(); + } + + /** + *

              Returns the number of inheritance hops between two classes.

              + * + * @param child the child class, may be {@code null} + * @param parent the parent class, may be {@code null} + * @return the number of generations between the child and parent; 0 if the same class; + * -1 if the classes are not related as child and parent (includes where either class is null) + * @since 3.2 + */ + public static int distance(final Class child, final Class parent) { + if (child == null || parent == null) { + return -1; + } + + if (child.equals(parent)) { + return 0; + } + + final Class cParent = child.getSuperclass(); + int d = BooleanUtils.toInteger(parent.equals(cParent)); + + if (d == 1) { + return d; + } + d += distance(cParent, parent); + return d > 0 ? d + 1 : -1; + } +} diff --git a/src/org/apache/commons/lang3/reflect/MemberUtils.java b/src/org/apache/commons/lang3/reflect/MemberUtils.java new file mode 100644 index 0000000..f54e84a --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/MemberUtils.java @@ -0,0 +1,304 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.commons.lang3.ClassUtils; + +/** + * Contains common code for working with {@link java.lang.reflect.Method Methods}/{@link java.lang.reflect.Constructor Constructors}, + * extracted and refactored from {@link MethodUtils} when it was imported from Commons BeanUtils. + * + * @since 2.5 + */ +abstract class MemberUtils { + // TODO extract an interface to implement compareParameterSets(...)? + + private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; + + /** Array of primitive number types ordered by "promotability" */ + private static final Class[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE, Short.TYPE, + Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE }; + + /** + * XXX Default access superclass workaround. + * + * When a {@code public} class has a default access superclass with {@code public} members, + * these members are accessible. Calling them from compiled code works fine. + * Unfortunately, on some JVMs, using reflection to invoke these members + * seems to (wrongly) prevent access even when the modifier is {@code public}. + * Calling {@code setAccessible(true)} solves the problem but will only work from + * sufficiently privileged code. Better workarounds would be gratefully + * accepted. + * @param o the AccessibleObject to set as accessible + * @return a boolean indicating whether the accessibility of the object was set to true. + */ + static boolean setAccessibleWorkaround(final AccessibleObject o) { + if (o == null || o.isAccessible()) { + return false; + } + final Member m = (Member) o; + if (!o.isAccessible() && Modifier.isPublic(m.getModifiers()) && isPackageAccess(m.getDeclaringClass().getModifiers())) { + try { + o.setAccessible(true); + return true; + } catch (final SecurityException e) { // NOPMD + // ignore in favor of subsequent IllegalAccessException + } + } + return false; + } + + /** + * Returns whether a given set of modifiers implies package access. + * @param modifiers to test + * @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected + */ + static boolean isPackageAccess(final int modifiers) { + return (modifiers & ACCESS_TEST) == 0; + } + + /** + * Returns whether a {@link Member} is accessible. + * @param m Member to check + * @return {@code true} if m is accessible + */ + static boolean isAccessible(final Member m) { + return m != null && Modifier.isPublic(m.getModifiers()) && !m.isSynthetic(); + } + + /** + * Compares the relative fitness of two Constructors in terms of how well they + * match a set of runtime parameter types, such that a list ordered + * by the results of the comparison would return the best match first + * (least). + * + * @param left the "left" Constructor + * @param right the "right" Constructor + * @param actual the runtime parameter types to match against + * {@code left}/{@code right} + * @return int consistent with {@code compare} semantics + * @since 3.5 + */ + static int compareConstructorFit(final Constructor left, final Constructor right, final Class[] actual) { + return compareParameterTypes(Executable.of(left), Executable.of(right), actual); + } + + /** + * Compares the relative fitness of two Methods in terms of how well they + * match a set of runtime parameter types, such that a list ordered + * by the results of the comparison would return the best match first + * (least). + * + * @param left the "left" Method + * @param right the "right" Method + * @param actual the runtime parameter types to match against + * {@code left}/{@code right} + * @return int consistent with {@code compare} semantics + * @since 3.5 + */ + static int compareMethodFit(final Method left, final Method right, final Class[] actual) { + return compareParameterTypes(Executable.of(left), Executable.of(right), actual); + } + + /** + * Compares the relative fitness of two Executables in terms of how well they + * match a set of runtime parameter types, such that a list ordered + * by the results of the comparison would return the best match first + * (least). + * + * @param left the "left" Executable + * @param right the "right" Executable + * @param actual the runtime parameter types to match against + * {@code left}/{@code right} + * @return int consistent with {@code compare} semantics + */ + private static int compareParameterTypes(final Executable left, final Executable right, final Class[] actual) { + final float leftCost = getTotalTransformationCost(actual, left); + final float rightCost = getTotalTransformationCost(actual, right); + return leftCost < rightCost ? -1 : rightCost < leftCost ? 1 : 0; + } + + /** + * Returns the sum of the object transformation cost for each class in the + * source argument list. + * @param srcArgs The source arguments + * @param executable The executable to calculate transformation costs for + * @return The total transformation cost + */ + private static float getTotalTransformationCost(final Class[] srcArgs, final Executable executable) { + final Class[] destArgs = executable.getParameterTypes(); + final boolean isVarArgs = executable.isVarArgs(); + + // "source" and "destination" are the actual and declared args respectively. + float totalCost = 0.0f; + final long normalArgsLen = isVarArgs ? destArgs.length-1 : destArgs.length; + if (srcArgs.length < normalArgsLen) { + return Float.MAX_VALUE; + } + for (int i = 0; i < normalArgsLen; i++) { + totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]); + } + if (isVarArgs) { + // When isVarArgs is true, srcArgs and dstArgs may differ in length. + // There are two special cases to consider: + final boolean noVarArgsPassed = srcArgs.length < destArgs.length; + final boolean explicitArrayForVarags = srcArgs.length == destArgs.length && srcArgs[srcArgs.length-1].isArray(); + + final float varArgsCost = 0.001f; + final Class destClass = destArgs[destArgs.length-1].getComponentType(); + if (noVarArgsPassed) { + // When no varargs passed, the best match is the most generic matching type, not the most specific. + totalCost += getObjectTransformationCost(destClass, Object.class) + varArgsCost; + } + else if (explicitArrayForVarags) { + final Class sourceClass = srcArgs[srcArgs.length-1].getComponentType(); + totalCost += getObjectTransformationCost(sourceClass, destClass) + varArgsCost; + } + else { + // This is typical varargs case. + for (int i = destArgs.length-1; i < srcArgs.length; i++) { + final Class srcClass = srcArgs[i]; + totalCost += getObjectTransformationCost(srcClass, destClass) + varArgsCost; + } + } + } + return totalCost; + } + + /** + * Gets the number of steps required needed to turn the source class into + * the destination class. This represents the number of steps in the object + * hierarchy graph. + * @param srcClass The source class + * @param destClass The destination class + * @return The cost of transforming an object + */ + private static float getObjectTransformationCost(Class srcClass, final Class destClass) { + if (destClass.isPrimitive()) { + return getPrimitivePromotionCost(srcClass, destClass); + } + float cost = 0.0f; + while (srcClass != null && !destClass.equals(srcClass)) { + if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) { + // slight penalty for interface match. + // we still want an exact match to override an interface match, + // but + // an interface match should override anything where we have to + // get a superclass. + cost += 0.25f; + break; + } + cost++; + srcClass = srcClass.getSuperclass(); + } + /* + * If the destination class is null, we've traveled all the way up to + * an Object match. We'll penalize this by adding 1.5 to the cost. + */ + if (srcClass == null) { + cost += 1.5f; + } + return cost; + } + + /** + * Gets the number of steps required to promote a primitive number to another + * type. + * @param srcClass the (primitive) source class + * @param destClass the (primitive) destination class + * @return The cost of promoting the primitive + */ + private static float getPrimitivePromotionCost(final Class srcClass, final Class destClass) { + float cost = 0.0f; + Class cls = srcClass; + if (!cls.isPrimitive()) { + // slight unwrapping penalty + cost += 0.1f; + cls = ClassUtils.wrapperToPrimitive(cls); + } + for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) { + if (cls == ORDERED_PRIMITIVE_TYPES[i]) { + cost += 0.1f; + if (i < ORDERED_PRIMITIVE_TYPES.length - 1) { + cls = ORDERED_PRIMITIVE_TYPES[i + 1]; + } + } + } + return cost; + } + + static boolean isMatchingMethod(final Method method, final Class[] parameterTypes) { + return MemberUtils.isMatchingExecutable(Executable.of(method), parameterTypes); + } + + static boolean isMatchingConstructor(final Constructor method, final Class[] parameterTypes) { + return MemberUtils.isMatchingExecutable(Executable.of(method), parameterTypes); + } + + private static boolean isMatchingExecutable(final Executable method, final Class[] parameterTypes) { + final Class[] methodParameterTypes = method.getParameterTypes(); + if (method.isVarArgs()) { + int i; + for (i = 0; i < methodParameterTypes.length - 1 && i < parameterTypes.length; i++) { + if (!ClassUtils.isAssignable(parameterTypes[i], methodParameterTypes[i], true)) { + return false; + } + } + final Class varArgParameterType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + for (; i < parameterTypes.length; i++) { + if (!ClassUtils.isAssignable(parameterTypes[i], varArgParameterType, true)) { + return false; + } + } + return true; + } + return ClassUtils.isAssignable(parameterTypes, methodParameterTypes, true); + } + + /** + *

              A class providing a subset of the API of java.lang.reflect.Executable in Java 1.8, + * providing a common representation for function signatures for Constructors and Methods.

              + */ + private static final class Executable { + private final Class[] parameterTypes; + private final boolean isVarArgs; + + private static Executable of(final Method method) { return new Executable(method); } + private static Executable of(final Constructor constructor) { return new Executable(constructor); } + + private Executable(final Method method) { + parameterTypes = method.getParameterTypes(); + isVarArgs = method.isVarArgs(); + } + + private Executable(final Constructor constructor) { + parameterTypes = constructor.getParameterTypes(); + isVarArgs = constructor.isVarArgs(); + } + + public Class[] getParameterTypes() { return parameterTypes; } + + public boolean isVarArgs() { return isVarArgs; } + } + +} diff --git a/src/org/apache/commons/lang3/reflect/MethodUtils.java b/src/org/apache/commons/lang3/reflect/MethodUtils.java new file mode 100644 index 0000000..d97bf84 --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/MethodUtils.java @@ -0,0 +1,874 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.ClassUtils.Interfaces; + +/** + *

              Utility reflection methods focused on {@link Method}s, originally from Commons BeanUtils. + * Differences from the BeanUtils version may be noted, especially where similar functionality + * already existed within Lang. + *

              + * + *

              Known Limitations

              + *

              Accessing Public Methods In A Default Access Superclass

              + *

              There is an issue when invoking {@code public} methods contained in a default access superclass on JREs prior to 1.4. + * Reflection locates these methods fine and correctly assigns them as {@code public}. + * However, an {@link IllegalAccessException} is thrown if the method is invoked.

              + * + *

              {@link MethodUtils} contains a workaround for this situation. + * It will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this method. + * If this call succeeds, then the method can be invoked as normal. + * This call will only succeed when the application has sufficient security privileges. + * If this call fails then the method may fail.

              + * + * @since 2.5 + */ +public class MethodUtils { + + /** + *

              {@link MethodUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as + * {@code MethodUtils.getAccessibleMethod(method)}.

              + * + *

              This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

              + */ + public MethodUtils() { + super(); + } + + /** + *

              Invokes a named method without parameters.

              + * + *

              This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

              + * + *

              This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

              + * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.4 + */ + public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

              Invokes a named method without parameters.

              + * + *

              This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

              + * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

              Invokes a named method whose parameter type matches the object type.

              + * + *

              This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

              + * + *

              This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

              + * + *

              This is a convenient wrapper for + * {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}. + *

              + * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, methodName, args, parameterTypes); + } + + /** + *

              Invokes a named method whose parameter type matches the object type.

              + * + *

              This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

              + * + *

              This is a convenient wrapper for + * {@link #invokeMethod(Object object,boolean forceAccess,String methodName, Object[] args, Class[] parameterTypes)}. + *

              + * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeMethod(object, forceAccess, methodName, args, parameterTypes); + } + + /** + *

              Invokes a named method whose parameter type matches the object type.

              + * + *

              This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

              + * + * @param object invoke method on this object + * @param forceAccess force access to invoke method even if it's not accessible + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + * @since 3.5 + */ + public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + args = ArrayUtils.nullToEmpty(args); + + final String messagePrefix; + Method method = null; + + if (forceAccess) { + messagePrefix = "No such method: "; + method = getMatchingMethod(object.getClass(), + methodName, parameterTypes); + if (method != null) { + if (!method.isAccessible()) { + method.setAccessible(true); + } + } + } else { + messagePrefix = "No such accessible method: "; + method = getMatchingAccessibleMethod(object.getClass(), + methodName, parameterTypes); + } + + if (method == null) { + throw new NoSuchMethodException(messagePrefix + + methodName + "() on object: " + + object.getClass().getName()); + } + args = toVarArgs(method, args); + + return method.invoke(object, args); + } + + /** + *

              Invokes a named method whose parameter type matches the object type.

              + * + *

              This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

              + * + *

              This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} object + * would match a {@code boolean} primitive.

              + * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the method invoked + * @throws IllegalAccessException if the requested method is not accessible via reflection + */ + public static Object invokeMethod(final Object object, final String methodName, + final Object[] args, final Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + return invokeMethod(object, false, methodName, args, parameterTypes); + } + + /** + *

              Invokes a method whose parameter types match exactly the object + * types.

              + * + *

              This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

              + * + * @param object invoke method on this object + * @param methodName get method with this name + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + * + * @since 3.4 + */ + public static Object invokeExactMethod(final Object object, final String methodName) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null); + } + + /** + *

              Invokes a method with no parameters.

              + * + *

              This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod}(Class,String,Class[])}.

              + * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactMethod(object, methodName, args, parameterTypes); + } + + /** + *

              Invokes a method whose parameter types match exactly the parameter + * types given.

              + * + *

              This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class,String,Class[])}.

              + * + * @param object invoke method on this object + * @param methodName get method with this name + * @param args use these arguments - treat null as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactMethod(final Object object, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(object.getClass(), methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on object: " + + object.getClass().getName()); + } + return method.invoke(object, args); + } + + /** + *

              Invokes a {@code static} method whose parameter types match exactly the parameter + * types given.

              + * + *

              This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

              + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getAccessibleMethod(cls, methodName, parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + return method.invoke(null, args); + } + + /** + *

              Invokes a named {@code static} method whose parameter type matches the object type.

              + * + *

              This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

              + * + *

              This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

              + * + *

              This is a convenient wrapper for + * {@link #invokeStaticMethod(Class, String, Object[], Class[])}. + *

              + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

              Invokes a named {@code static} method whose parameter type matches the object type.

              + * + *

              This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.

              + * + *

              This method supports calls to methods taking primitive parameters + * via passing in wrapping classes. So, for example, a {@code Boolean} class + * would match a {@code boolean} primitive.

              + * + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @param parameterTypes match these parameters - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeStaticMethod(final Class cls, final String methodName, + Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Method method = getMatchingAccessibleMethod(cls, methodName, + parameterTypes); + if (method == null) { + throw new NoSuchMethodException("No such accessible method: " + + methodName + "() on class: " + cls.getName()); + } + args = toVarArgs(method, args); + return method.invoke(null, args); + } + + private static Object[] toVarArgs(final Method method, Object[] args) { + if (method.isVarArgs()) { + final Class[] methodParameterTypes = method.getParameterTypes(); + args = getVarArgs(args, methodParameterTypes); + } + return args; + } + + /** + *

              Given an arguments array passed to a varargs method, return an array of arguments in the canonical form, + * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type. + *

              + * + * @param args the array of arguments passed to the varags method + * @param methodParameterTypes the declared array of method parameter types + * @return an array of the variadic arguments passed to the method + * @since 3.5 + */ + static Object[] getVarArgs(final Object[] args, final Class[] methodParameterTypes) { + if (args.length == methodParameterTypes.length + && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) { + // The args array is already in the canonical form for the method. + return args; + } + + // Construct a new array matching the method's declared parameter types. + final Object[] newArgs = new Object[methodParameterTypes.length]; + + // Copy the normal (non-varargs) parameters + System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1); + + // Construct a new array for the variadic parameters + final Class varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + final int varArgLength = args.length - methodParameterTypes.length + 1; + + Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength); + // Copy the variadic arguments into the varargs array. + System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength); + + if(varArgComponentType.isPrimitive()) { + // unbox from wrapper type to primitive type + varArgsArray = ArrayUtils.toPrimitive(varArgsArray); + } + + // Store the varargs array in the last position of the array to return + newArgs[methodParameterTypes.length - 1] = varArgsArray; + + // Return the canonical varargs array. + return newArgs; + } + + /** + *

              Invokes a {@code static} method whose parameter types match exactly the object + * types.

              + * + *

              This uses reflection to invoke the method obtained from a call to + * {@link #getAccessibleMethod(Class, String, Class[])}.

              + * + * @param cls invoke static method on this class + * @param methodName get method with this name + * @param args use these arguments - treat {@code null} as empty array + * @return The value returned by the invoked method + * + * @throws NoSuchMethodException if there is no such accessible method + * @throws InvocationTargetException wraps an exception thrown by the + * method invoked + * @throws IllegalAccessException if the requested method is not accessible + * via reflection + */ + public static Object invokeExactStaticMethod(final Class cls, final String methodName, + Object... args) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + args = ArrayUtils.nullToEmpty(args); + final Class[] parameterTypes = ClassUtils.toClass(args); + return invokeExactStaticMethod(cls, methodName, args, parameterTypes); + } + + /** + *

              Returns an accessible method (that is, one that can be invoked via + * reflection) with given name and parameters. If no such method + * can be found, return {@code null}. + * This is just a convenience wrapper for + * {@link #getAccessibleMethod(Method)}.

              + * + * @param cls get method from this class + * @param methodName get method with this name + * @param parameterTypes with these parameters types + * @return The accessible method + */ + public static Method getAccessibleMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + try { + return getAccessibleMethod(cls.getMethod(methodName, + parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

              Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified Method. If no such method + * can be found, return {@code null}.

              + * + * @param method The method that we wish to call + * @return The accessible method + */ + public static Method getAccessibleMethod(Method method) { + if (!MemberUtils.isAccessible(method)) { + return null; + } + // If the declaring class is public, we are done + final Class cls = method.getDeclaringClass(); + if (Modifier.isPublic(cls.getModifiers())) { + return method; + } + final String methodName = method.getName(); + final Class[] parameterTypes = method.getParameterTypes(); + + // Check the implemented interfaces and subinterfaces + method = getAccessibleMethodFromInterfaceNest(cls, methodName, + parameterTypes); + + // Check the superclass chain + if (method == null) { + method = getAccessibleMethodFromSuperclass(cls, methodName, + parameterTypes); + } + return method; + } + + /** + *

              Returns an accessible method (that is, one that can be invoked via + * reflection) by scanning through the superclasses. If no such method + * can be found, return {@code null}.

              + * + * @param cls Class to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromSuperclass(final Class cls, + final String methodName, final Class... parameterTypes) { + Class parentClass = cls.getSuperclass(); + while (parentClass != null) { + if (Modifier.isPublic(parentClass.getModifiers())) { + try { + return parentClass.getMethod(methodName, parameterTypes); + } catch (final NoSuchMethodException e) { + return null; + } + } + parentClass = parentClass.getSuperclass(); + } + return null; + } + + /** + *

              Returns an accessible method (that is, one that can be invoked via + * reflection) that implements the specified method, by scanning through + * all implemented interfaces and subinterfaces. If no such method + * can be found, return {@code null}.

              + * + *

              There isn't any good reason why this method must be {@code private}. + * It is because there doesn't seem any reason why other classes should + * call this rather than the higher level methods.

              + * + * @param cls Parent class for the interfaces to be checked + * @param methodName Method name of the method we wish to call + * @param parameterTypes The parameter type signatures + * @return the accessible method or {@code null} if not found + */ + private static Method getAccessibleMethodFromInterfaceNest(Class cls, + final String methodName, final Class... parameterTypes) { + // Search up the superclass chain + for (; cls != null; cls = cls.getSuperclass()) { + + // Check the implemented interfaces of the parent class + final Class[] interfaces = cls.getInterfaces(); + for (Class anInterface : interfaces) { + // Is this interface public? + if (!Modifier.isPublic(anInterface.getModifiers())) { + continue; + } + // Does the method exist on this interface? + try { + return anInterface.getDeclaredMethod(methodName, + parameterTypes); + } catch (final NoSuchMethodException e) { // NOPMD + /* + * Swallow, if no method is found after the loop then this + * method returns null. + */ + } + // Recursively check our parent interfaces + final Method method = getAccessibleMethodFromInterfaceNest(anInterface, + methodName, parameterTypes); + if (method != null) { + return method; + } + } + } + return null; + } + + /** + *

              Finds an accessible method that matches the given name and has compatible parameters. + * Compatible parameters mean that every method parameter is assignable from + * the given parameters. + * In other words, it finds a method with the given name + * that will take the parameters given.

              + * + *

              This method is used by + * {@link + * #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}. + *

              + * + *

              This method can match primitive parameter by passing in wrapper classes. + * For example, a {@code Boolean} will match a primitive {@code boolean} + * parameter. + *

              + * + * @param cls find method in this class + * @param methodName find method with this name + * @param parameterTypes find method with most compatible parameters + * @return The accessible method + */ + public static Method getMatchingAccessibleMethod(final Class cls, + final String methodName, final Class... parameterTypes) { + try { + final Method method = cls.getMethod(methodName, parameterTypes); + MemberUtils.setAccessibleWorkaround(method); + return method; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow the exception + } + // search through all methods + Method bestMatch = null; + final Method[] methods = cls.getMethods(); + for (final Method method : methods) { + // compare name and parameters + if (method.getName().equals(methodName) && + MemberUtils.isMatchingMethod(method, parameterTypes)) { + // get accessible version of method + final Method accessibleMethod = getAccessibleMethod(method); + if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit( + accessibleMethod, + bestMatch, + parameterTypes) < 0)) { + bestMatch = accessibleMethod; + } + } + } + if (bestMatch != null) { + MemberUtils.setAccessibleWorkaround(bestMatch); + } + + if (bestMatch != null && bestMatch.isVarArgs() && bestMatch.getParameterTypes().length > 0 && parameterTypes.length > 0) { + final Class[] methodParameterTypes = bestMatch.getParameterTypes(); + final Class methodParameterComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); + final String methodParameterComponentTypeName = ClassUtils.primitiveToWrapper(methodParameterComponentType).getName(); + final String parameterTypeName = parameterTypes[parameterTypes.length - 1].getName(); + final String parameterTypeSuperClassName = parameterTypes[parameterTypes.length - 1].getSuperclass().getName(); + + if (!methodParameterComponentTypeName.equals(parameterTypeName) + && !methodParameterComponentTypeName.equals(parameterTypeSuperClassName)) { + return null; + } + } + + return bestMatch; + } + + /** + *

              Retrieves a method whether or not it's accessible. If no such method + * can be found, return {@code null}.

              + * @param cls The class that will be subjected to the method search + * @param methodName The method that we wish to call + * @param parameterTypes Argument class types + * @return The method + * + * @since 3.5 + */ + public static Method getMatchingMethod(final Class cls, final String methodName, + final Class... parameterTypes) { + Validate.notNull(cls, "Null class not allowed."); + Validate.notEmpty(methodName, "Null or blank methodName not allowed."); + + // Address methods in superclasses + Method[] methodArray = cls.getDeclaredMethods(); + final List> superclassList = ClassUtils.getAllSuperclasses(cls); + for (final Class klass : superclassList) { + methodArray = ArrayUtils.addAll(methodArray, klass.getDeclaredMethods()); + } + + Method inexactMatch = null; + for (final Method method : methodArray) { + if (methodName.equals(method.getName()) && + Objects.deepEquals(parameterTypes, method.getParameterTypes())) { + return method; + } else if (methodName.equals(method.getName()) && + ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) { + if (inexactMatch == null) { + inexactMatch = method; + } else if (distance(parameterTypes, method.getParameterTypes()) + < distance(parameterTypes, inexactMatch.getParameterTypes())) { + inexactMatch = method; + } + } + + } + return inexactMatch; + } + + /** + *

              Returns the aggregate number of inheritance hops between assignable argument class types. Returns -1 + * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.

              + * @param classArray + * @param toClassArray + * @return the aggregate number of inheritance hops between assignable argument class types. + */ + private static int distance(final Class[] classArray, final Class[] toClassArray) { + int answer = 0; + + if (!ClassUtils.isAssignable(classArray, toClassArray, true)) { + return -1; + } + for (int offset = 0; offset < classArray.length; offset++) { + // Note InheritanceUtils.distance() uses different scoring system. + if (classArray[offset].equals(toClassArray[offset])) { + continue; + } else if (ClassUtils.isAssignable(classArray[offset], toClassArray[offset], true) + && !ClassUtils.isAssignable(classArray[offset], toClassArray[offset], false)) { + answer++; + } else { + answer = answer + 2; + } + } + + return answer; + } + + /** + * Get the hierarchy of overridden methods down to {@code result} respecting generics. + * @param method lowest to consider + * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false + * @return Set<Method> in ascending order from sub- to superclass + * @throws NullPointerException if the specified method is {@code null} + * @since 3.2 + */ + public static Set getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { + Validate.notNull(method); + final Set result = new LinkedHashSet<>(); + result.add(method); + + final Class[] parameterTypes = method.getParameterTypes(); + + final Class declaringClass = method.getDeclaringClass(); + + final Iterator> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); + //skip the declaring class :P + hierarchy.next(); + hierarchyTraversal: while (hierarchy.hasNext()) { + final Class c = hierarchy.next(); + final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); + if (m == null) { + continue; + } + if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { + // matches without generics + result.add(m); + continue; + } + // necessary to get arguments every time in the case that we are including interfaces + final Map, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); + for (int i = 0; i < parameterTypes.length; i++) { + final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); + final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); + if (!TypeUtils.equals(childType, parentType)) { + continue hierarchyTraversal; + } + } + result.add(m); + } + return result; + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched + * @return an array of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static Method[] getMethodsWithAnnotation(final Class cls, final Class annotationCls) { + final List annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls); + return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]); + } + + /** + * Gets all methods of the given class that are annotated with the given annotation. + * @param cls + * the {@link Class} to query + * @param annotationCls + * the {@link Annotation} that must be present on a method to be matched + * @return a list of Methods (possibly empty). + * @throws IllegalArgumentException + * if the class or annotation are {@code null} + * @since 3.4 + */ + public static List getMethodsListWithAnnotation(final Class cls, final Class annotationCls) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(annotationCls != null, "The annotation class must not be null"); + final Method[] allMethods = cls.getMethods(); + final List annotatedMethods = new ArrayList<>(); + for (final Method method : allMethods) { + if (method.getAnnotation(annotationCls) != null) { + annotatedMethods.add(method); + } + } + return annotatedMethods; + } + +} diff --git a/src/org/apache/commons/lang3/reflect/TypeLiteral.java b/src/org/apache/commons/lang3/reflect/TypeLiteral.java new file mode 100644 index 0000000..bead33f --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/TypeLiteral.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; + +import org.apache.commons.lang3.Validate; + +/** + *

              Type literal comparable to {@code javax.enterprise.util.TypeLiteral}, + * made generally available outside the JEE context. Allows the passing around of + * a "token" that represents a type in a typesafe manner, as opposed to + * passing the (non-parameterized) {@link Type} object itself. Consider:

              + *

              + * You might see such a typesafe API as: + *

              + * class Typesafe {
              + *   <T> T obtain(Class<T> type, ...);
              + * }
              + * 
              + * Consumed in the manner of: + *
              + * Foo foo = typesafe.obtain(Foo.class, ...);
              + * 
              + * Yet, you run into problems when you want to do this with a parameterized type: + *
              + * List<String> listOfString = typesafe.obtain(List.class, ...); // could only give us a raw List
              + * 
              + * {@code java.lang.reflect.Type} might provide some value: + *
              + * Type listOfStringType = ...; // firstly, how to obtain this? Doable, but not straightforward.
              + * List<String> listOfString = (List<String>) typesafe.obtain(listOfStringType, ...); // nongeneric Type would necessitate a cast
              + * 
              + * The "type literal" concept was introduced to provide an alternative, i.e.: + *
              + * class Typesafe {
              + *   <T> T obtain(TypeLiteral<T> type, ...);
              + * }
              + * 
              + * Consuming code looks like: + *
              + * List<String> listOfString = typesafe.obtain(new TypeLiteral<List<String>>() {}, ...);
              + * 
              + *

              + * This has the effect of "jumping up" a level to tie a {@code java.lang.reflect.Type} + * to a type variable while simultaneously making it short work to obtain a + * {@code Type} instance for any given type, inline. + *

              + *

              Additionally {@link TypeLiteral} implements the {@link Typed} interface which + * is a generalization of this concept, and which may be implemented in custom classes. + * It is suggested that APIs be defined in terms of the interface, in the following manner: + *

              + *
              + *   <T> T obtain(Typed<T> typed, ...);
              + * 
              + * + * @since 3.2 + */ +public abstract class TypeLiteral implements Typed { + + @SuppressWarnings("rawtypes") + private static final TypeVariable> T = TypeLiteral.class.getTypeParameters()[0]; + + /** + * Represented type. + */ + public final Type value; + + private final String toString; + + /** + * The default constructor. + */ + protected TypeLiteral() { + this.value = + Validate.notNull(TypeUtils.getTypeArguments(getClass(), TypeLiteral.class).get(T), + "%s does not assign type parameter %s", getClass(), TypeUtils.toLongString(T)); + + this.toString = String.format("%s<%s>", TypeLiteral.class.getSimpleName(), TypeUtils.toString(value)); + } + + @Override + public final boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof TypeLiteral == false) { + return false; + } + final TypeLiteral other = (TypeLiteral) obj; + return TypeUtils.equals(value, other.value); + } + + @Override + public int hashCode() { + return 37 << 4 | value.hashCode(); + } + + @Override + public String toString() { + return toString; + } + + @Override + public Type getType() { + return value; + } +} diff --git a/src/org/apache/commons/lang3/reflect/TypeUtils.java b/src/org/apache/commons/lang3/reflect/TypeUtils.java new file mode 100644 index 0000000..8db6ca4 --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/TypeUtils.java @@ -0,0 +1,1854 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.builder.Builder; + +/** + *

              Utility methods focusing on type inspection, particularly with regard to + * generics.

              + * + * @since 3.0 + */ +public class TypeUtils { + + /** + * {@link WildcardType} builder. + * @since 3.2 + */ + public static class WildcardTypeBuilder implements Builder { + /** + * Constructor + */ + private WildcardTypeBuilder() { + } + + private Type[] upperBounds; + private Type[] lowerBounds; + + /** + * Specify upper bounds of the wildcard type to build. + * @param bounds to set + * @return {@code this} + */ + public WildcardTypeBuilder withUpperBounds(final Type... bounds) { + this.upperBounds = bounds; + return this; + } + + /** + * Specify lower bounds of the wildcard type to build. + * @param bounds to set + * @return {@code this} + */ + public WildcardTypeBuilder withLowerBounds(final Type... bounds) { + this.lowerBounds = bounds; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public WildcardType build() { + return new WildcardTypeImpl(upperBounds, lowerBounds); + } + } + + /** + * GenericArrayType implementation class. + * @since 3.2 + */ + private static final class GenericArrayTypeImpl implements GenericArrayType { + private final Type componentType; + + /** + * Constructor + * @param componentType of this array type + */ + private GenericArrayTypeImpl(final Type componentType) { + this.componentType = componentType; + } + + /** + * {@inheritDoc} + */ + @Override + public Type getGenericComponentType() { + return componentType; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return TypeUtils.toString(this); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(final Object obj) { + return obj == this || obj instanceof GenericArrayType && TypeUtils.equals(this, (GenericArrayType) obj); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = 67 << 4; + result |= componentType.hashCode(); + return result; + } + } + + /** + * ParameterizedType implementation class. + * @since 3.2 + */ + private static final class ParameterizedTypeImpl implements ParameterizedType { + private final Class raw; + private final Type useOwner; + private final Type[] typeArguments; + + /** + * Constructor + * @param raw type + * @param useOwner owner type to use, if any + * @param typeArguments formal type arguments + */ + private ParameterizedTypeImpl(final Class raw, final Type useOwner, final Type[] typeArguments) { + this.raw = raw; + this.useOwner = useOwner; + this.typeArguments = typeArguments.clone(); + } + + /** + * {@inheritDoc} + */ + @Override + public Type getRawType() { + return raw; + } + + /** + * {@inheritDoc} + */ + @Override + public Type getOwnerType() { + return useOwner; + } + + /** + * {@inheritDoc} + */ + @Override + public Type[] getActualTypeArguments() { + return typeArguments.clone(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return TypeUtils.toString(this); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(final Object obj) { + return obj == this || obj instanceof ParameterizedType && TypeUtils.equals(this, ((ParameterizedType) obj)); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = 71 << 4; + result |= raw.hashCode(); + result <<= 4; + result |= Objects.hashCode(useOwner); + result <<= 8; + result |= Arrays.hashCode(typeArguments); + return result; + } + } + + /** + * WildcardType implementation class. + * @since 3.2 + */ + private static final class WildcardTypeImpl implements WildcardType { + private static final Type[] EMPTY_BOUNDS = new Type[0]; + + private final Type[] upperBounds; + private final Type[] lowerBounds; + + /** + * Constructor + * @param upperBounds of this type + * @param lowerBounds of this type + */ + private WildcardTypeImpl(final Type[] upperBounds, final Type[] lowerBounds) { + this.upperBounds = ObjectUtils.defaultIfNull(upperBounds, EMPTY_BOUNDS); + this.lowerBounds = ObjectUtils.defaultIfNull(lowerBounds, EMPTY_BOUNDS); + } + + /** + * {@inheritDoc} + */ + @Override + public Type[] getUpperBounds() { + return upperBounds.clone(); + } + + /** + * {@inheritDoc} + */ + @Override + public Type[] getLowerBounds() { + return lowerBounds.clone(); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return TypeUtils.toString(this); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(final Object obj) { + return obj == this || obj instanceof WildcardType && TypeUtils.equals(this, (WildcardType) obj); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = 73 << 8; + result |= Arrays.hashCode(upperBounds); + result <<= 8; + result |= Arrays.hashCode(lowerBounds); + return result; + } + } + + /** + * A wildcard instance matching {@code ?}. + * @since 3.2 + */ + public static final WildcardType WILDCARD_ALL = wildcardType().withUpperBounds(Object.class).build(); + + /** + *

              {@code TypeUtils} instances should NOT be constructed in standard + * programming. Instead, the class should be used as + * {@code TypeUtils.isAssignable(cls, toClass)}.

              This + * constructor is public to permit tools that require a JavaBean instance to + * operate.

              + */ + public TypeUtils() { + super(); + } + + /** + *

              Checks if the subject type may be implicitly cast to the target type + * following the Java generics rules. If both types are {@link Class} + * objects, the method returns the result of + * {@link ClassUtils#isAssignable(Class, Class)}.

              + * + * @param type the subject type to be assigned to the target type + * @param toType the target type + * @return {@code true} if {@code type} is assignable to {@code toType}. + */ + public static boolean isAssignable(final Type type, final Type toType) { + return isAssignable(type, toType, null); + } + + /** + *

              Checks if the subject type may be implicitly cast to the target type + * following the Java generics rules.

              + * + * @param type the subject type to be assigned to the target type + * @param toType the target type + * @param typeVarAssigns optional map of type variable assignments + * @return {@code true} if {@code type} is assignable to {@code toType}. + */ + private static boolean isAssignable(final Type type, final Type toType, + final Map, Type> typeVarAssigns) { + if (toType == null || toType instanceof Class) { + return isAssignable(type, (Class) toType); + } + + if (toType instanceof ParameterizedType) { + return isAssignable(type, (ParameterizedType) toType, typeVarAssigns); + } + + if (toType instanceof GenericArrayType) { + return isAssignable(type, (GenericArrayType) toType, typeVarAssigns); + } + + if (toType instanceof WildcardType) { + return isAssignable(type, (WildcardType) toType, typeVarAssigns); + } + + if (toType instanceof TypeVariable) { + return isAssignable(type, (TypeVariable) toType, typeVarAssigns); + } + + throw new IllegalStateException("found an unhandled type: " + toType); + } + + /** + *

              Checks if the subject type may be implicitly cast to the target class + * following the Java generics rules.

              + * + * @param type the subject type to be assigned to the target type + * @param toClass the target class + * @return {@code true} if {@code type} is assignable to {@code toClass}. + */ + private static boolean isAssignable(final Type type, final Class toClass) { + if (type == null) { + // consistency with ClassUtils.isAssignable() behavior + return toClass == null || !toClass.isPrimitive(); + } + + // only a null type can be assigned to null type which + // would have cause the previous to return true + if (toClass == null) { + return false; + } + + // all types are assignable to themselves + if (toClass.equals(type)) { + return true; + } + + if (type instanceof Class) { + // just comparing two classes + return ClassUtils.isAssignable((Class) type, toClass); + } + + if (type instanceof ParameterizedType) { + // only have to compare the raw type to the class + return isAssignable(getRawType((ParameterizedType) type), toClass); + } + + // * + if (type instanceof TypeVariable) { + // if any of the bounds are assignable to the class, then the + // type is assignable to the class. + for (final Type bound : ((TypeVariable) type).getBounds()) { + if (isAssignable(bound, toClass)) { + return true; + } + } + + return false; + } + + // the only classes to which a generic array type can be assigned + // are class Object and array classes + if (type instanceof GenericArrayType) { + return toClass.equals(Object.class) + || toClass.isArray() + && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass + .getComponentType()); + } + + // wildcard types are not assignable to a class (though one would think + // "? super Object" would be assignable to Object) + if (type instanceof WildcardType) { + return false; + } + + throw new IllegalStateException("found an unhandled type: " + type); + } + + /** + *

              Checks if the subject type may be implicitly cast to the target + * parameterized type following the Java generics rules.

              + * + * @param type the subject type to be assigned to the target type + * @param toParameterizedType the target parameterized type + * @param typeVarAssigns a map with type variables + * @return {@code true} if {@code type} is assignable to {@code toType}. + */ + private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType, + final Map, Type> typeVarAssigns) { + if (type == null) { + return true; + } + + // only a null type can be assigned to null type which + // would have cause the previous to return true + if (toParameterizedType == null) { + return false; + } + + // all types are assignable to themselves + if (toParameterizedType.equals(type)) { + return true; + } + + // get the target type's raw type + final Class toClass = getRawType(toParameterizedType); + // get the subject type's type arguments including owner type arguments + // and supertype arguments up to and including the target class. + final Map, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null); + + // null means the two types are not compatible + if (fromTypeVarAssigns == null) { + return false; + } + + // compatible types, but there's no type arguments. this is equivalent + // to comparing Map< ?, ? > to Map, and raw types are always assignable + // to parameterized types. + if (fromTypeVarAssigns.isEmpty()) { + return true; + } + + // get the target type's type arguments including owner type arguments + final Map, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType, + toClass, typeVarAssigns); + + // now to check each type argument + for (final TypeVariable var : toTypeVarAssigns.keySet()) { + final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns); + final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns); + + if (toTypeArg == null && fromTypeArg instanceof Class) { + continue; + } + + // parameters must either be absent from the subject type, within + // the bounds of the wildcard type, or be an exact match to the + // parameters of the target type. + if (fromTypeArg != null + && !toTypeArg.equals(fromTypeArg) + && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg, + typeVarAssigns))) { + return false; + } + } + return true; + } + + /** + * Look up {@code var} in {@code typeVarAssigns} transitively, + * i.e. keep looking until the value found is not a type variable. + * @param var the type variable to look up + * @param typeVarAssigns the map used for the look up + * @return Type or {@code null} if some variable was not in the map + * @since 3.2 + */ + private static Type unrollVariableAssignments(TypeVariable var, final Map, Type> typeVarAssigns) { + Type result; + do { + result = typeVarAssigns.get(var); + if (result instanceof TypeVariable && !result.equals(var)) { + var = (TypeVariable) result; + continue; + } + break; + } while (true); + return result; + } + + /** + *

              Checks if the subject type may be implicitly cast to the target + * generic array type following the Java generics rules.

              + * + * @param type the subject type to be assigned to the target type + * @param toGenericArrayType the target generic array type + * @param typeVarAssigns a map with type variables + * @return {@code true} if {@code type} is assignable to + * {@code toGenericArrayType}. + */ + private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType, + final Map, Type> typeVarAssigns) { + if (type == null) { + return true; + } + + // only a null type can be assigned to null type which + // would have cause the previous to return true + if (toGenericArrayType == null) { + return false; + } + + // all types are assignable to themselves + if (toGenericArrayType.equals(type)) { + return true; + } + + final Type toComponentType = toGenericArrayType.getGenericComponentType(); + + if (type instanceof Class) { + final Class cls = (Class) type; + + // compare the component types + return cls.isArray() + && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns); + } + + if (type instanceof GenericArrayType) { + // compare the component types + return isAssignable(((GenericArrayType) type).getGenericComponentType(), + toComponentType, typeVarAssigns); + } + + if (type instanceof WildcardType) { + // so long as one of the upper bounds is assignable, it's good + for (final Type bound : getImplicitUpperBounds((WildcardType) type)) { + if (isAssignable(bound, toGenericArrayType)) { + return true; + } + } + + return false; + } + + if (type instanceof TypeVariable) { + // probably should remove the following logic and just return false. + // type variables cannot specify arrays as bounds. + for (final Type bound : getImplicitBounds((TypeVariable) type)) { + if (isAssignable(bound, toGenericArrayType)) { + return true; + } + } + + return false; + } + + if (type instanceof ParameterizedType) { + // the raw type of a parameterized type is never an array or + // generic array, otherwise the declaration would look like this: + // Collection[]< ? extends String > collection; + return false; + } + + throw new IllegalStateException("found an unhandled type: " + type); + } + + /** + *

              Checks if the subject type may be implicitly cast to the target + * wildcard type following the Java generics rules.

              + * + * @param type the subject type to be assigned to the target type + * @param toWildcardType the target wildcard type + * @param typeVarAssigns a map with type variables + * @return {@code true} if {@code type} is assignable to + * {@code toWildcardType}. + */ + private static boolean isAssignable(final Type type, final WildcardType toWildcardType, + final Map, Type> typeVarAssigns) { + if (type == null) { + return true; + } + + // only a null type can be assigned to null type which + // would have cause the previous to return true + if (toWildcardType == null) { + return false; + } + + // all types are assignable to themselves + if (toWildcardType.equals(type)) { + return true; + } + + final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType); + final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType); + + if (type instanceof WildcardType) { + final WildcardType wildcardType = (WildcardType) type; + final Type[] upperBounds = getImplicitUpperBounds(wildcardType); + final Type[] lowerBounds = getImplicitLowerBounds(wildcardType); + + for (Type toBound : toUpperBounds) { + // if there are assignments for unresolved type variables, + // now's the time to substitute them. + toBound = substituteTypeVariables(toBound, typeVarAssigns); + + // each upper bound of the subject type has to be assignable to + // each + // upper bound of the target type + for (final Type bound : upperBounds) { + if (!isAssignable(bound, toBound, typeVarAssigns)) { + return false; + } + } + } + + for (Type toBound : toLowerBounds) { + // if there are assignments for unresolved type variables, + // now's the time to substitute them. + toBound = substituteTypeVariables(toBound, typeVarAssigns); + + // each lower bound of the target type has to be assignable to + // each + // lower bound of the subject type + for (final Type bound : lowerBounds) { + if (!isAssignable(toBound, bound, typeVarAssigns)) { + return false; + } + } + } + return true; + } + + for (final Type toBound : toUpperBounds) { + // if there are assignments for unresolved type variables, + // now's the time to substitute them. + if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns), + typeVarAssigns)) { + return false; + } + } + + for (final Type toBound : toLowerBounds) { + // if there are assignments for unresolved type variables, + // now's the time to substitute them. + if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type, + typeVarAssigns)) { + return false; + } + } + return true; + } + + /** + *

              Checks if the subject type may be implicitly cast to the target type + * variable following the Java generics rules.

              + * + * @param type the subject type to be assigned to the target type + * @param toTypeVariable the target type variable + * @param typeVarAssigns a map with type variables + * @return {@code true} if {@code type} is assignable to + * {@code toTypeVariable}. + */ + private static boolean isAssignable(final Type type, final TypeVariable toTypeVariable, + final Map, Type> typeVarAssigns) { + if (type == null) { + return true; + } + + // only a null type can be assigned to null type which + // would have cause the previous to return true + if (toTypeVariable == null) { + return false; + } + + // all types are assignable to themselves + if (toTypeVariable.equals(type)) { + return true; + } + + if (type instanceof TypeVariable) { + // a type variable is assignable to another type variable, if + // and only if the former is the latter, extends the latter, or + // is otherwise a descendant of the latter. + final Type[] bounds = getImplicitBounds((TypeVariable) type); + + for (final Type bound : bounds) { + if (isAssignable(bound, toTypeVariable, typeVarAssigns)) { + return true; + } + } + } + + if (type instanceof Class || type instanceof ParameterizedType + || type instanceof GenericArrayType || type instanceof WildcardType) { + return false; + } + + throw new IllegalStateException("found an unhandled type: " + type); + } + + /** + *

              Find the mapping for {@code type} in {@code typeVarAssigns}.

              + * + * @param type the type to be replaced + * @param typeVarAssigns the map with type variables + * @return the replaced type + * @throws IllegalArgumentException if the type cannot be substituted + */ + private static Type substituteTypeVariables(final Type type, final Map, Type> typeVarAssigns) { + if (type instanceof TypeVariable && typeVarAssigns != null) { + final Type replacementType = typeVarAssigns.get(type); + + if (replacementType == null) { + throw new IllegalArgumentException("missing assignment type for type variable " + + type); + } + return replacementType; + } + return type; + } + + /** + *

              Retrieves all the type arguments for this parameterized type + * including owner hierarchy arguments such as + * {@code Outer.Inner.DeepInner} . + * The arguments are returned in a + * {@link Map} specifying the argument type for each {@link TypeVariable}. + *

              + * + * @param type specifies the subject parameterized type from which to + * harvest the parameters. + * @return a {@code Map} of the type arguments to their respective type + * variables. + */ + public static Map, Type> getTypeArguments(final ParameterizedType type) { + return getTypeArguments(type, getRawType(type), null); + } + + /** + *

              Gets the type arguments of a class/interface based on a subtype. For + * instance, this method will determine that both of the parameters for the + * interface {@link Map} are {@link Object} for the subtype + * {@link java.util.Properties Properties} even though the subtype does not + * directly implement the {@code Map} interface.

              + *

              This method returns {@code null} if {@code type} is not assignable to + * {@code toClass}. It returns an empty map if none of the classes or + * interfaces in its inheritance hierarchy specify any type arguments.

              + *

              A side effect of this method is that it also retrieves the type + * arguments for the classes and interfaces that are part of the hierarchy + * between {@code type} and {@code toClass}. So with the above + * example, this method will also determine that the type arguments for + * {@link java.util.Hashtable Hashtable} are also both {@code Object}. + * In cases where the interface specified by {@code toClass} is + * (indirectly) implemented more than once (e.g. where {@code toClass} + * specifies the interface {@link java.lang.Iterable Iterable} and + * {@code type} specifies a parameterized type that implements both + * {@link java.util.Set Set} and {@link java.util.Collection Collection}), + * this method will look at the inheritance hierarchy of only one of the + * implementations/subclasses; the first interface encountered that isn't a + * subinterface to one of the others in the {@code type} to + * {@code toClass} hierarchy.

              + * + * @param type the type from which to determine the type parameters of + * {@code toClass} + * @param toClass the class whose type parameters are to be determined based + * on the subtype {@code type} + * @return a {@code Map} of the type assignments for the type variables in + * each type in the inheritance hierarchy from {@code type} to + * {@code toClass} inclusive. + */ + public static Map, Type> getTypeArguments(final Type type, final Class toClass) { + return getTypeArguments(type, toClass, null); + } + + /** + *

              Return a map of the type arguments of {@code type} in the context of {@code toClass}.

              + * + * @param type the type in question + * @param toClass the class + * @param subtypeVarAssigns a map with type variables + * @return the {@code Map} with type arguments + */ + private static Map, Type> getTypeArguments(final Type type, final Class toClass, + final Map, Type> subtypeVarAssigns) { + if (type instanceof Class) { + return getTypeArguments((Class) type, toClass, subtypeVarAssigns); + } + + if (type instanceof ParameterizedType) { + return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns); + } + + if (type instanceof GenericArrayType) { + return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass + .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns); + } + + // since wildcard types are not assignable to classes, should this just + // return null? + if (type instanceof WildcardType) { + for (final Type bound : getImplicitUpperBounds((WildcardType) type)) { + // find the first bound that is assignable to the target class + if (isAssignable(bound, toClass)) { + return getTypeArguments(bound, toClass, subtypeVarAssigns); + } + } + + return null; + } + + if (type instanceof TypeVariable) { + for (final Type bound : getImplicitBounds((TypeVariable) type)) { + // find the first bound that is assignable to the target class + if (isAssignable(bound, toClass)) { + return getTypeArguments(bound, toClass, subtypeVarAssigns); + } + } + + return null; + } + throw new IllegalStateException("found an unhandled type: " + type); + } + + /** + *

              Return a map of the type arguments of a parameterized type in the context of {@code toClass}.

              + * + * @param parameterizedType the parameterized type + * @param toClass the class + * @param subtypeVarAssigns a map with type variables + * @return the {@code Map} with type arguments + */ + private static Map, Type> getTypeArguments( + final ParameterizedType parameterizedType, final Class toClass, + final Map, Type> subtypeVarAssigns) { + final Class cls = getRawType(parameterizedType); + + // make sure they're assignable + if (!isAssignable(cls, toClass)) { + return null; + } + + final Type ownerType = parameterizedType.getOwnerType(); + Map, Type> typeVarAssigns; + + if (ownerType instanceof ParameterizedType) { + // get the owner type arguments first + final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType; + typeVarAssigns = getTypeArguments(parameterizedOwnerType, + getRawType(parameterizedOwnerType), subtypeVarAssigns); + } else { + // no owner, prep the type variable assignments map + typeVarAssigns = subtypeVarAssigns == null ? new HashMap, Type>() + : new HashMap<>(subtypeVarAssigns); + } + + // get the subject parameterized type's arguments + final Type[] typeArgs = parameterizedType.getActualTypeArguments(); + // and get the corresponding type variables from the raw class + final TypeVariable[] typeParams = cls.getTypeParameters(); + + // map the arguments to their respective type variables + for (int i = 0; i < typeParams.length; i++) { + final Type typeArg = typeArgs[i]; + typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns + .get(typeArg) : typeArg); + } + + if (toClass.equals(cls)) { + // target class has been reached. Done. + return typeVarAssigns; + } + + // walk the inheritance hierarchy until the target class is reached + return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns); + } + + /** + *

              Return a map of the type arguments of a class in the context of {@code toClass}.

              + * + * @param cls the class in question + * @param toClass the context class + * @param subtypeVarAssigns a map with type variables + * @return the {@code Map} with type arguments + */ + private static Map, Type> getTypeArguments(Class cls, final Class toClass, + final Map, Type> subtypeVarAssigns) { + // make sure they're assignable + if (!isAssignable(cls, toClass)) { + return null; + } + + // can't work with primitives + if (cls.isPrimitive()) { + // both classes are primitives? + if (toClass.isPrimitive()) { + // dealing with widening here. No type arguments to be + // harvested with these two types. + return new HashMap<>(); + } + + // work with wrapper the wrapper class instead of the primitive + cls = ClassUtils.primitiveToWrapper(cls); + } + + // create a copy of the incoming map, or an empty one if it's null + final HashMap, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap, Type>() + : new HashMap<>(subtypeVarAssigns); + + // has target class been reached? + if (toClass.equals(cls)) { + return typeVarAssigns; + } + + // walk the inheritance hierarchy until the target class is reached + return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns); + } + + /** + *

              Tries to determine the type arguments of a class/interface based on a + * super parameterized type's type arguments. This method is the inverse of + * {@link #getTypeArguments(Type, Class)} which gets a class/interface's + * type arguments based on a subtype. It is far more limited in determining + * the type arguments for the subject class's type variables in that it can + * only determine those parameters that map from the subject {@link Class} + * object to the supertype.

              Example: {@link java.util.TreeSet + * TreeSet} sets its parameter as the parameter for + * {@link java.util.NavigableSet NavigableSet}, which in turn sets the + * parameter of {@link java.util.SortedSet}, which in turn sets the + * parameter of {@link Set}, which in turn sets the parameter of + * {@link java.util.Collection}, which in turn sets the parameter of + * {@link java.lang.Iterable}. Since {@code TreeSet}'s parameter maps + * (indirectly) to {@code Iterable}'s parameter, it will be able to + * determine that based on the super type {@code Iterable>>}, the parameter of + * {@code TreeSet} is {@code ? extends Map>}.

              + * + * @param cls the class whose type parameters are to be determined, not {@code null} + * @param superType the super type from which {@code cls}'s type + * arguments are to be determined, not {@code null} + * @return a {@code Map} of the type assignments that could be determined + * for the type variables in each type in the inheritance hierarchy from + * {@code type} to {@code toClass} inclusive. + */ + public static Map, Type> determineTypeArguments(final Class cls, + final ParameterizedType superType) { + Validate.notNull(cls, "cls is null"); + Validate.notNull(superType, "superType is null"); + + final Class superClass = getRawType(superType); + + // compatibility check + if (!isAssignable(cls, superClass)) { + return null; + } + + if (cls.equals(superClass)) { + return getTypeArguments(superType, superClass, null); + } + + // get the next class in the inheritance hierarchy + final Type midType = getClosestParentType(cls, superClass); + + // can only be a class or a parameterized type + if (midType instanceof Class) { + return determineTypeArguments((Class) midType, superType); + } + + final ParameterizedType midParameterizedType = (ParameterizedType) midType; + final Class midClass = getRawType(midParameterizedType); + // get the type variables of the mid class that map to the type + // arguments of the super class + final Map, Type> typeVarAssigns = determineTypeArguments(midClass, superType); + // map the arguments of the mid type to the class type variables + mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns); + + return typeVarAssigns; + } + + /** + *

              Performs a mapping of type variables.

              + * + * @param the generic type of the class in question + * @param cls the class in question + * @param parameterizedType the parameterized type + * @param typeVarAssigns the map to be filled + */ + private static void mapTypeVariablesToArguments(final Class cls, + final ParameterizedType parameterizedType, final Map, Type> typeVarAssigns) { + // capture the type variables from the owner type that have assignments + final Type ownerType = parameterizedType.getOwnerType(); + + if (ownerType instanceof ParameterizedType) { + // recursion to make sure the owner's owner type gets processed + mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns); + } + + // parameterizedType is a generic interface/class (or it's in the owner + // hierarchy of said interface/class) implemented/extended by the class + // cls. Find out which type variables of cls are type arguments of + // parameterizedType: + final Type[] typeArgs = parameterizedType.getActualTypeArguments(); + + // of the cls's type variables that are arguments of parameterizedType, + // find out which ones can be determined from the super type's arguments + final TypeVariable[] typeVars = getRawType(parameterizedType).getTypeParameters(); + + // use List view of type parameters of cls so the contains() method can be used: + final List>> typeVarList = Arrays.asList(cls + .getTypeParameters()); + + for (int i = 0; i < typeArgs.length; i++) { + final TypeVariable typeVar = typeVars[i]; + final Type typeArg = typeArgs[i]; + + // argument of parameterizedType is a type variable of cls + if (typeVarList.contains(typeArg) + // type variable of parameterizedType has an assignment in + // the super type. + && typeVarAssigns.containsKey(typeVar)) { + // map the assignment to the cls's type variable + typeVarAssigns.put((TypeVariable) typeArg, typeVarAssigns.get(typeVar)); + } + } + } + + /** + *

              Get the closest parent type to the + * super class specified by {@code superClass}.

              + * + * @param cls the class in question + * @param superClass the super class + * @return the closes parent type + */ + private static Type getClosestParentType(final Class cls, final Class superClass) { + // only look at the interfaces if the super class is also an interface + if (superClass.isInterface()) { + // get the generic interfaces of the subject class + final Type[] interfaceTypes = cls.getGenericInterfaces(); + // will hold the best generic interface match found + Type genericInterface = null; + + // find the interface closest to the super class + for (final Type midType : interfaceTypes) { + Class midClass = null; + + if (midType instanceof ParameterizedType) { + midClass = getRawType((ParameterizedType) midType); + } else if (midType instanceof Class) { + midClass = (Class) midType; + } else { + throw new IllegalStateException("Unexpected generic" + + " interface type found: " + midType); + } + + // check if this interface is further up the inheritance chain + // than the previously found match + if (isAssignable(midClass, superClass) + && isAssignable(genericInterface, (Type) midClass)) { + genericInterface = midType; + } + } + + // found a match? + if (genericInterface != null) { + return genericInterface; + } + } + + // none of the interfaces were descendants of the target class, so the + // super class has to be one, instead + return cls.getGenericSuperclass(); + } + + /** + *

              Checks if the given value can be assigned to the target type + * following the Java generics rules.

              + * + * @param value the value to be checked + * @param type the target type + * @return {@code true} if {@code value} is an instance of {@code type}. + */ + public static boolean isInstance(final Object value, final Type type) { + if (type == null) { + return false; + } + + return value == null ? !(type instanceof Class) || !((Class) type).isPrimitive() + : isAssignable(value.getClass(), type, null); + } + + /** + *

              This method strips out the redundant upper bound types in type + * variable types and wildcard types (or it would with wildcard types if + * multiple upper bounds were allowed).

              Example, with the variable + * type declaration: + * + *

              <K extends java.util.Collection<String> &
              +     * java.util.List<String>>
              + * + *

              + * since {@code List} is a subinterface of {@code Collection}, + * this method will return the bounds as if the declaration had been: + *

              + * + *
              <K extends java.util.List<String>>
              + * + * @param bounds an array of types representing the upper bounds of either + * {@link WildcardType} or {@link TypeVariable}, not {@code null}. + * @return an array containing the values from {@code bounds} minus the + * redundant types. + */ + public static Type[] normalizeUpperBounds(final Type[] bounds) { + Validate.notNull(bounds, "null value specified for bounds array"); + // don't bother if there's only one (or none) type + if (bounds.length < 2) { + return bounds; + } + + final Set types = new HashSet<>(bounds.length); + + for (final Type type1 : bounds) { + boolean subtypeFound = false; + + for (final Type type2 : bounds) { + if (type1 != type2 && isAssignable(type2, type1, null)) { + subtypeFound = true; + break; + } + } + + if (!subtypeFound) { + types.add(type1); + } + } + + return types.toArray(new Type[types.size()]); + } + + /** + *

              Returns an array containing the sole type of {@link Object} if + * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it + * returns the result of {@link TypeVariable#getBounds()} passed into + * {@link #normalizeUpperBounds}.

              + * + * @param typeVariable the subject type variable, not {@code null} + * @return a non-empty array containing the bounds of the type variable. + */ + public static Type[] getImplicitBounds(final TypeVariable typeVariable) { + Validate.notNull(typeVariable, "typeVariable is null"); + final Type[] bounds = typeVariable.getBounds(); + + return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds); + } + + /** + *

              Returns an array containing the sole value of {@link Object} if + * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise, + * it returns the result of {@link WildcardType#getUpperBounds()} + * passed into {@link #normalizeUpperBounds}.

              + * + * @param wildcardType the subject wildcard type, not {@code null} + * @return a non-empty array containing the upper bounds of the wildcard + * type. + */ + public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) { + Validate.notNull(wildcardType, "wildcardType is null"); + final Type[] bounds = wildcardType.getUpperBounds(); + + return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds); + } + + /** + *

              Returns an array containing a single value of {@code null} if + * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise, + * it returns the result of {@link WildcardType#getLowerBounds()}.

              + * + * @param wildcardType the subject wildcard type, not {@code null} + * @return a non-empty array containing the lower bounds of the wildcard + * type. + */ + public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) { + Validate.notNull(wildcardType, "wildcardType is null"); + final Type[] bounds = wildcardType.getLowerBounds(); + + return bounds.length == 0 ? new Type[] { null } : bounds; + } + + /** + *

              Determines whether or not specified types satisfy the bounds of their + * mapped type variables. When a type parameter extends another (such as + * {@code }), uses another as a type parameter (such as + * {@code >}), or otherwise depends on + * another type variable to be specified, the dependencies must be included + * in {@code typeVarAssigns}.

              + * + * @param typeVarAssigns specifies the potential types to be assigned to the + * type variables, not {@code null}. + * @return whether or not the types can be assigned to their respective type + * variables. + */ + public static boolean typesSatisfyVariables(final Map, Type> typeVarAssigns) { + Validate.notNull(typeVarAssigns, "typeVarAssigns is null"); + // all types must be assignable to all the bounds of the their mapped + // type variable. + for (final Map.Entry, Type> entry : typeVarAssigns.entrySet()) { + final TypeVariable typeVar = entry.getKey(); + final Type type = entry.getValue(); + + for (final Type bound : getImplicitBounds(typeVar)) { + if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns), + typeVarAssigns)) { + return false; + } + } + } + return true; + } + + /** + *

              Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.

              + * + * @param parameterizedType the type to be converted + * @return the corresponding {@code Class} object + * @throws IllegalStateException if the conversion fails + */ + private static Class getRawType(final ParameterizedType parameterizedType) { + final Type rawType = parameterizedType.getRawType(); + + // check if raw type is a Class object + // not currently necessary, but since the return type is Type instead of + // Class, there's enough reason to believe that future versions of Java + // may return other Type implementations. And type-safety checking is + // rarely a bad idea. + if (!(rawType instanceof Class)) { + throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType); + } + + return (Class) rawType; + } + + /** + *

              Get the raw type of a Java type, given its context. Primarily for use + * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do + * not know the runtime type of {@code type}: if you know you have a + * {@link Class} instance, it is already raw; if you know you have a + * {@link ParameterizedType}, its raw type is only a method call away.

              + * + * @param type to resolve + * @param assigningType type to be resolved against + * @return the resolved {@link Class} object or {@code null} if + * the type could not be resolved + */ + public static Class getRawType(final Type type, final Type assigningType) { + if (type instanceof Class) { + // it is raw, no problem + return (Class) type; + } + + if (type instanceof ParameterizedType) { + // simple enough to get the raw type of a ParameterizedType + return getRawType((ParameterizedType) type); + } + + if (type instanceof TypeVariable) { + if (assigningType == null) { + return null; + } + + // get the entity declaring this type variable + final Object genericDeclaration = ((TypeVariable) type).getGenericDeclaration(); + + // can't get the raw type of a method- or constructor-declared type + // variable + if (!(genericDeclaration instanceof Class)) { + return null; + } + + // get the type arguments for the declaring class/interface based + // on the enclosing type + final Map, Type> typeVarAssigns = getTypeArguments(assigningType, + (Class) genericDeclaration); + + // enclosingType has to be a subclass (or subinterface) of the + // declaring type + if (typeVarAssigns == null) { + return null; + } + + // get the argument assigned to this type variable + final Type typeArgument = typeVarAssigns.get(type); + + if (typeArgument == null) { + return null; + } + + // get the argument for this type variable + return getRawType(typeArgument, assigningType); + } + + if (type instanceof GenericArrayType) { + // get raw component type + final Class rawComponentType = getRawType(((GenericArrayType) type) + .getGenericComponentType(), assigningType); + + // create array type from raw component type and return its class + return Array.newInstance(rawComponentType, 0).getClass(); + } + + // (hand-waving) this is not the method you're looking for + if (type instanceof WildcardType) { + return null; + } + + throw new IllegalArgumentException("unknown type: " + type); + } + + /** + * Learn whether the specified type denotes an array type. + * @param type the type to be checked + * @return {@code true} if {@code type} is an array class or a {@link GenericArrayType}. + */ + public static boolean isArrayType(final Type type) { + return type instanceof GenericArrayType || type instanceof Class && ((Class) type).isArray(); + } + + /** + * Get the array component type of {@code type}. + * @param type the type to be checked + * @return component type or null if type is not an array type + */ + public static Type getArrayComponentType(final Type type) { + if (type instanceof Class) { + final Class clazz = (Class) type; + return clazz.isArray() ? clazz.getComponentType() : null; + } + if (type instanceof GenericArrayType) { + return ((GenericArrayType) type).getGenericComponentType(); + } + return null; + } + + /** + * Get a type representing {@code type} with variable assignments "unrolled." + * + * @param typeArguments as from {@link TypeUtils#getTypeArguments(Type, Class)} + * @param type the type to unroll variable assignments for + * @return Type + * @since 3.2 + */ + public static Type unrollVariables(Map, Type> typeArguments, final Type type) { + if (typeArguments == null) { + typeArguments = Collections., Type> emptyMap(); + } + if (containsTypeVariables(type)) { + if (type instanceof TypeVariable) { + return unrollVariables(typeArguments, typeArguments.get(type)); + } + if (type instanceof ParameterizedType) { + final ParameterizedType p = (ParameterizedType) type; + final Map, Type> parameterizedTypeArguments; + if (p.getOwnerType() == null) { + parameterizedTypeArguments = typeArguments; + } else { + parameterizedTypeArguments = new HashMap<>(typeArguments); + parameterizedTypeArguments.putAll(TypeUtils.getTypeArguments(p)); + } + final Type[] args = p.getActualTypeArguments(); + for (int i = 0; i < args.length; i++) { + final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]); + if (unrolled != null) { + args[i] = unrolled; + } + } + return parameterizeWithOwner(p.getOwnerType(), (Class) p.getRawType(), args); + } + if (type instanceof WildcardType) { + final WildcardType wild = (WildcardType) type; + return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds())) + .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build(); + } + } + return type; + } + + /** + * Local helper method to unroll variables in a type bounds array. + * + * @param typeArguments assignments {@link Map} + * @param bounds in which to expand variables + * @return {@code bounds} with any variables reassigned + * @since 3.2 + */ + private static Type[] unrollBounds(final Map, Type> typeArguments, final Type[] bounds) { + Type[] result = bounds; + int i = 0; + for (; i < result.length; i++) { + final Type unrolled = unrollVariables(typeArguments, result[i]); + if (unrolled == null) { + result = ArrayUtils.remove(result, i--); + } else { + result[i] = unrolled; + } + } + return result; + } + + /** + * Learn, recursively, whether any of the type parameters associated with {@code type} are bound to variables. + * + * @param type the type to check for type variables + * @return boolean + * @since 3.2 + */ + public static boolean containsTypeVariables(final Type type) { + if (type instanceof TypeVariable) { + return true; + } + if (type instanceof Class) { + return ((Class) type).getTypeParameters().length > 0; + } + if (type instanceof ParameterizedType) { + for (final Type arg : ((ParameterizedType) type).getActualTypeArguments()) { + if (containsTypeVariables(arg)) { + return true; + } + } + return false; + } + if (type instanceof WildcardType) { + final WildcardType wild = (WildcardType) type; + return containsTypeVariables(TypeUtils.getImplicitLowerBounds(wild)[0]) + || containsTypeVariables(TypeUtils.getImplicitUpperBounds(wild)[0]); + } + return false; + } + + /** + * Create a parameterized type instance. + * + * @param raw the raw class to create a parameterized type instance for + * @param typeArguments the types used for parameterization + * @return {@link ParameterizedType} + * @since 3.2 + */ + public static final ParameterizedType parameterize(final Class raw, final Type... typeArguments) { + return parameterizeWithOwner(null, raw, typeArguments); + } + + /** + * Create a parameterized type instance. + * + * @param raw the raw class to create a parameterized type instance for + * @param typeArgMappings the mapping used for parameterization + * @return {@link ParameterizedType} + * @since 3.2 + */ + public static final ParameterizedType parameterize(final Class raw, + final Map, Type> typeArgMappings) { + Validate.notNull(raw, "raw class is null"); + Validate.notNull(typeArgMappings, "typeArgMappings is null"); + return parameterizeWithOwner(null, raw, extractTypeArgumentsFrom(typeArgMappings, raw.getTypeParameters())); + } + + /** + * Create a parameterized type instance. + * + * @param owner the owning type + * @param raw the raw class to create a parameterized type instance for + * @param typeArguments the types used for parameterization + * + * @return {@link ParameterizedType} + * @since 3.2 + */ + public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class raw, + final Type... typeArguments) { + Validate.notNull(raw, "raw class is null"); + final Type useOwner; + if (raw.getEnclosingClass() == null) { + Validate.isTrue(owner == null, "no owner allowed for top-level %s", raw); + useOwner = null; + } else if (owner == null) { + useOwner = raw.getEnclosingClass(); + } else { + Validate.isTrue(TypeUtils.isAssignable(owner, raw.getEnclosingClass()), + "%s is invalid owner type for parameterized %s", owner, raw); + useOwner = owner; + } + Validate.noNullElements(typeArguments, "null type argument at index %s"); + Validate.isTrue(raw.getTypeParameters().length == typeArguments.length, + "invalid number of type parameters specified: expected %d, got %d", raw.getTypeParameters().length, + typeArguments.length); + + return new ParameterizedTypeImpl(raw, useOwner, typeArguments); + } + + /** + * Create a parameterized type instance. + * + * @param owner the owning type + * @param raw the raw class to create a parameterized type instance for + * @param typeArgMappings the mapping used for parameterization + * @return {@link ParameterizedType} + * @since 3.2 + */ + public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class raw, + final Map, Type> typeArgMappings) { + Validate.notNull(raw, "raw class is null"); + Validate.notNull(typeArgMappings, "typeArgMappings is null"); + return parameterizeWithOwner(owner, raw, extractTypeArgumentsFrom(typeArgMappings, raw.getTypeParameters())); + } + + /** + * Helper method to establish the formal parameters for a parameterized type. + * @param mappings map containing the assignments + * @param variables expected map keys + * @return array of map values corresponding to specified keys + */ + private static Type[] extractTypeArgumentsFrom(final Map, Type> mappings, final TypeVariable[] variables) { + final Type[] result = new Type[variables.length]; + int index = 0; + for (final TypeVariable var : variables) { + Validate.isTrue(mappings.containsKey(var), "missing argument mapping for %s", toString(var)); + result[index++] = mappings.get(var); + } + return result; + } + + /** + * Get a {@link WildcardTypeBuilder}. + * @return {@link WildcardTypeBuilder} + * @since 3.2 + */ + public static WildcardTypeBuilder wildcardType() { + return new WildcardTypeBuilder(); + } + + /** + * Create a generic array type instance. + * + * @param componentType the type of the elements of the array. For example the component type of {@code boolean[]} + * is {@code boolean} + * @return {@link GenericArrayType} + * @since 3.2 + */ + public static GenericArrayType genericArrayType(final Type componentType) { + return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType is null")); + } + + /** + * Check equality of types. + * + * @param t1 the first type + * @param t2 the second type + * @return boolean + * @since 3.2 + */ + public static boolean equals(final Type t1, final Type t2) { + if (Objects.equals(t1, t2)) { + return true; + } + if (t1 instanceof ParameterizedType) { + return equals((ParameterizedType) t1, t2); + } + if (t1 instanceof GenericArrayType) { + return equals((GenericArrayType) t1, t2); + } + if (t1 instanceof WildcardType) { + return equals((WildcardType) t1, t2); + } + return false; + } + + /** + * Learn whether {@code t} equals {@code p}. + * @param p LHS + * @param t RHS + * @return boolean + * @since 3.2 + */ + private static boolean equals(final ParameterizedType p, final Type t) { + if (t instanceof ParameterizedType) { + final ParameterizedType other = (ParameterizedType) t; + if (equals(p.getRawType(), other.getRawType()) && equals(p.getOwnerType(), other.getOwnerType())) { + return equals(p.getActualTypeArguments(), other.getActualTypeArguments()); + } + } + return false; + } + + /** + * Learn whether {@code t} equals {@code a}. + * @param a LHS + * @param t RHS + * @return boolean + * @since 3.2 + */ + private static boolean equals(final GenericArrayType a, final Type t) { + return t instanceof GenericArrayType + && equals(a.getGenericComponentType(), ((GenericArrayType) t).getGenericComponentType()); + } + + /** + * Learn whether {@code t} equals {@code w}. + * @param w LHS + * @param t RHS + * @return boolean + * @since 3.2 + */ + private static boolean equals(final WildcardType w, final Type t) { + if (t instanceof WildcardType) { + final WildcardType other = (WildcardType) t; + return equals(getImplicitLowerBounds(w), getImplicitLowerBounds(other)) + && equals(getImplicitUpperBounds(w), getImplicitUpperBounds(other)); + } + return false; + } + + /** + * Learn whether {@code t1} equals {@code t2}. + * @param t1 LHS + * @param t2 RHS + * @return boolean + * @since 3.2 + */ + private static boolean equals(final Type[] t1, final Type[] t2) { + if (t1.length == t2.length) { + for (int i = 0; i < t1.length; i++) { + if (!equals(t1[i], t2[i])) { + return false; + } + } + return true; + } + return false; + } + + /** + * Present a given type as a Java-esque String. + * + * @param type the type to create a String representation for, not {@code null} + * @return String + * @since 3.2 + */ + public static String toString(final Type type) { + Validate.notNull(type); + if (type instanceof Class) { + return classToString((Class) type); + } + if (type instanceof ParameterizedType) { + return parameterizedTypeToString((ParameterizedType) type); + } + if (type instanceof WildcardType) { + return wildcardTypeToString((WildcardType) type); + } + if (type instanceof TypeVariable) { + return typeVariableToString((TypeVariable) type); + } + if (type instanceof GenericArrayType) { + return genericArrayTypeToString((GenericArrayType) type); + } + throw new IllegalArgumentException(ObjectUtils.identityToString(type)); + } + + /** + * Format a {@link TypeVariable} including its {@link GenericDeclaration}. + * + * @param var the type variable to create a String representation for, not {@code null} + * @return String + * @since 3.2 + */ + public static String toLongString(final TypeVariable var) { + Validate.notNull(var, "var is null"); + final StringBuilder buf = new StringBuilder(); + final GenericDeclaration d = var.getGenericDeclaration(); + if (d instanceof Class) { + Class c = (Class) d; + while (true) { + if (c.getEnclosingClass() == null) { + buf.insert(0, c.getName()); + break; + } + buf.insert(0, c.getSimpleName()).insert(0, '.'); + c = c.getEnclosingClass(); + } + } else if (d instanceof Type) {// not possible as of now + buf.append(toString((Type) d)); + } else { + buf.append(d); + } + return buf.append(':').append(typeVariableToString(var)).toString(); + } + + /** + * Wrap the specified {@link Type} in a {@link Typed} wrapper. + * + * @param inferred generic type + * @param type to wrap + * @return Typed<T> + * @since 3.2 + */ + public static Typed wrap(final Type type) { + return new Typed() { + @Override + public Type getType() { + return type; + } + }; + } + + /** + * Wrap the specified {@link Class} in a {@link Typed} wrapper. + * + * @param generic type + * @param type to wrap + * @return Typed<T> + * @since 3.2 + */ + public static Typed wrap(final Class type) { + return TypeUtils. wrap((Type) type); + } + + /** + * Format a {@link Class} as a {@link String}. + * @param c {@code Class} to format + * @return String + * @since 3.2 + */ + private static String classToString(final Class c) { + if (c.isArray()) { + return toString(c.getComponentType()) + "[]"; + } + + final StringBuilder buf = new StringBuilder(); + + if (c.getEnclosingClass() != null) { + buf.append(classToString(c.getEnclosingClass())).append('.').append(c.getSimpleName()); + } else { + buf.append(c.getName()); + } + if (c.getTypeParameters().length > 0) { + buf.append('<'); + appendAllTo(buf, ", ", c.getTypeParameters()); + buf.append('>'); + } + return buf.toString(); + } + + /** + * Format a {@link TypeVariable} as a {@link String}. + * @param v {@code TypeVariable} to format + * @return String + * @since 3.2 + */ + private static String typeVariableToString(final TypeVariable v) { + final StringBuilder buf = new StringBuilder(v.getName()); + final Type[] bounds = v.getBounds(); + if (bounds.length > 0 && !(bounds.length == 1 && Object.class.equals(bounds[0]))) { + buf.append(" extends "); + appendAllTo(buf, " & ", v.getBounds()); + } + return buf.toString(); + } + + /** + * Format a {@link ParameterizedType} as a {@link String}. + * @param p {@code ParameterizedType} to format + * @return String + * @since 3.2 + */ + private static String parameterizedTypeToString(final ParameterizedType p) { + final StringBuilder buf = new StringBuilder(); + + final Type useOwner = p.getOwnerType(); + final Class raw = (Class) p.getRawType(); + final Type[] typeArguments = p.getActualTypeArguments(); + if (useOwner == null) { + buf.append(raw.getName()); + } else { + if (useOwner instanceof Class) { + buf.append(((Class) useOwner).getName()); + } else { + buf.append(useOwner.toString()); + } + buf.append('.').append(raw.getSimpleName()); + } + + appendAllTo(buf.append('<'), ", ", typeArguments).append('>'); + return buf.toString(); + } + + /** + * Format a {@link WildcardType} as a {@link String}. + * @param w {@code WildcardType} to format + * @return String + * @since 3.2 + */ + private static String wildcardTypeToString(final WildcardType w) { + final StringBuilder buf = new StringBuilder().append('?'); + final Type[] lowerBounds = w.getLowerBounds(); + final Type[] upperBounds = w.getUpperBounds(); + if (lowerBounds.length > 1 || lowerBounds.length == 1 && lowerBounds[0] != null) { + appendAllTo(buf.append(" super "), " & ", lowerBounds); + } else if (upperBounds.length > 1 || upperBounds.length == 1 && !Object.class.equals(upperBounds[0])) { + appendAllTo(buf.append(" extends "), " & ", upperBounds); + } + return buf.toString(); + } + + /** + * Format a {@link GenericArrayType} as a {@link String}. + * @param g {@code GenericArrayType} to format + * @return String + * @since 3.2 + */ + private static String genericArrayTypeToString(final GenericArrayType g) { + return String.format("%s[]", toString(g.getGenericComponentType())); + } + + /** + * Append {@code types} to {@code buf} with separator {@code sep}. + * @param buf destination + * @param sep separator + * @param types to append + * @return {@code buf} + * @since 3.2 + */ + private static StringBuilder appendAllTo(final StringBuilder buf, final String sep, final Type... types) { + Validate.notEmpty(Validate.noNullElements(types)); + if (types.length > 0) { + buf.append(toString(types[0])); + for (int i = 1; i < types.length; i++) { + buf.append(sep).append(toString(types[i])); + } + } + return buf; + } + +} diff --git a/src/org/apache/commons/lang3/reflect/Typed.java b/src/org/apache/commons/lang3/reflect/Typed.java new file mode 100644 index 0000000..4841f5c --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/Typed.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.reflect; + +import java.lang.reflect.Type; + +/** + * Generalization of "has a type." + * @see TypeLiteral + * @since 3.2 + */ +public interface Typed { + + /** + * Get the {@link Type} represented by this entity. + * + * @return Type + */ + Type getType(); +} diff --git a/src/org/apache/commons/lang3/reflect/package-info.java b/src/org/apache/commons/lang3/reflect/package-info.java new file mode 100644 index 0000000..5483643 --- /dev/null +++ b/src/org/apache/commons/lang3/reflect/package-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Accumulates common high-level uses of the {@code java.lang.reflect} APIs.

              + *

              These classes are immutable, and therefore thread-safe.

              + * + * @since 3.0 + */ +package org.apache.commons.lang3.reflect; diff --git a/src/org/apache/commons/lang3/text/CompositeFormat.java b/src/org/apache/commons/lang3/text/CompositeFormat.java new file mode 100644 index 0000000..bac62ec --- /dev/null +++ b/src/org/apache/commons/lang3/text/CompositeFormat.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParseException; +import java.text.ParsePosition; + +/** + * Formats using one formatter and parses using a different formatter. An + * example of use for this would be a webapp where data is taken in one way and + * stored in a database another way. + * @deprecated as of 3.6, use commons-text + * + * CompositeFormat instead + */ +@Deprecated +public class CompositeFormat extends Format { + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = -4329119827877627683L; + + /** The parser to use. */ + private final Format parser; + /** The formatter to use. */ + private final Format formatter; + + /** + * Create a format that points its parseObject method to one implementation + * and its format method to another. + * + * @param parser implementation + * @param formatter implementation + */ + public CompositeFormat(final Format parser, final Format formatter) { + this.parser = parser; + this.formatter = formatter; + } + + /** + * Uses the formatter Format instance. + * + * @param obj the object to format + * @param toAppendTo the {@link StringBuffer} to append to + * @param pos the FieldPosition to use (or ignore). + * @return toAppendTo + * @see Format#format(Object, StringBuffer, FieldPosition) + */ + @Override // Therefore has to use StringBuffer + public StringBuffer format(final Object obj, final StringBuffer toAppendTo, + final FieldPosition pos) { + return formatter.format(obj, toAppendTo, pos); + } + + /** + * Uses the parser Format instance. + * + * @param source the String source + * @param pos the ParsePosition containing the position to parse from, will + * be updated according to parsing success (index) or failure + * (error index) + * @return the parsed Object + * @see Format#parseObject(String, ParsePosition) + */ + @Override + public Object parseObject(final String source, final ParsePosition pos) { + return parser.parseObject(source, pos); + } + + /** + * Provides access to the parser Format implementation. + * + * @return parser Format implementation + */ + public Format getParser() { + return this.parser; + } + + /** + * Provides access to the parser Format implementation. + * + * @return formatter Format implementation + */ + public Format getFormatter() { + return this.formatter; + } + + /** + * Utility method to parse and then reformat a String. + * + * @param input String to reformat + * @return A reformatted String + * @throws ParseException thrown by parseObject(String) call + */ + public String reformat(final String input) throws ParseException { + return format(parseObject(input)); + } + +} diff --git a/src/org/apache/commons/lang3/text/ExtendedMessageFormat.java b/src/org/apache/commons/lang3/text/ExtendedMessageFormat.java new file mode 100644 index 0000000..75e53a0 --- /dev/null +++ b/src/org/apache/commons/lang3/text/ExtendedMessageFormat.java @@ -0,0 +1,532 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.text.Format; +import java.text.MessageFormat; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.Validate; + +/** + * Extends java.text.MessageFormat to allow pluggable/additional formatting + * options for embedded format elements. Client code should specify a registry + * of FormatFactory instances associated with String + * format names. This registry will be consulted when the format elements are + * parsed from the message pattern. In this way custom patterns can be specified, + * and the formats supported by java.text.MessageFormat can be overridden + * at the format and/or format style level (see MessageFormat). A "format element" + * embedded in the message pattern is specified (()? signifies optionality):
              + * {argument-number(,format-name + * (,format-style)?)?} + * + *

              + * format-name and format-style values are trimmed of surrounding whitespace + * in the manner of java.text.MessageFormat. If format-name denotes + * FormatFactory formatFactoryInstance in registry, a Format + * matching format-name and format-style is requested from + * formatFactoryInstance. If this is successful, the Format + * found is used for this format element. + *

              + * + *

              NOTICE: The various subformat mutator methods are considered unnecessary; they exist on the parent + * class to allow the type of customization which it is the job of this class to provide in + * a configurable fashion. These methods have thus been disabled and will throw + * UnsupportedOperationException if called. + *

              + * + *

              Limitations inherited from java.text.MessageFormat:

              + *
                + *
              • When using "choice" subformats, support for nested formatting instructions is limited + * to that provided by the base class.
              • + *
              • Thread-safety of Formats, including MessageFormat and thus + * ExtendedMessageFormat, is not guaranteed.
              • + *
              + * + * @since 2.4 + * @deprecated as of 3.6, use commons-text + * + * ExtendedMessageFormat instead + */ +@Deprecated +public class ExtendedMessageFormat extends MessageFormat { + private static final long serialVersionUID = -2362048321261811743L; + private static final int HASH_SEED = 31; + + private static final String DUMMY_PATTERN = ""; + private static final char START_FMT = ','; + private static final char END_FE = '}'; + private static final char START_FE = '{'; + private static final char QUOTE = '\''; + + private String toPattern; + private final Map registry; + + /** + * Create a new ExtendedMessageFormat for the default locale. + * + * @param pattern the pattern to use, not null + * @throws IllegalArgumentException in case of a bad pattern. + */ + public ExtendedMessageFormat(final String pattern) { + this(pattern, Locale.getDefault()); + } + + /** + * Create a new ExtendedMessageFormat. + * + * @param pattern the pattern to use, not null + * @param locale the locale to use, not null + * @throws IllegalArgumentException in case of a bad pattern. + */ + public ExtendedMessageFormat(final String pattern, final Locale locale) { + this(pattern, locale, null); + } + + /** + * Create a new ExtendedMessageFormat for the default locale. + * + * @param pattern the pattern to use, not null + * @param registry the registry of format factories, may be null + * @throws IllegalArgumentException in case of a bad pattern. + */ + public ExtendedMessageFormat(final String pattern, final Map registry) { + this(pattern, Locale.getDefault(), registry); + } + + /** + * Create a new ExtendedMessageFormat. + * + * @param pattern the pattern to use, not null + * @param locale the locale to use, not null + * @param registry the registry of format factories, may be null + * @throws IllegalArgumentException in case of a bad pattern. + */ + public ExtendedMessageFormat(final String pattern, final Locale locale, final Map registry) { + super(DUMMY_PATTERN); + setLocale(locale); + this.registry = registry; + applyPattern(pattern); + } + + /** + * {@inheritDoc} + */ + @Override + public String toPattern() { + return toPattern; + } + + /** + * Apply the specified pattern. + * + * @param pattern String + */ + @Override + public final void applyPattern(final String pattern) { + if (registry == null) { + super.applyPattern(pattern); + toPattern = super.toPattern(); + return; + } + final ArrayList foundFormats = new ArrayList<>(); + final ArrayList foundDescriptions = new ArrayList<>(); + final StringBuilder stripCustom = new StringBuilder(pattern.length()); + + final ParsePosition pos = new ParsePosition(0); + final char[] c = pattern.toCharArray(); + int fmtCount = 0; + while (pos.getIndex() < pattern.length()) { + switch (c[pos.getIndex()]) { + case QUOTE: + appendQuotedString(pattern, pos, stripCustom); + break; + case START_FE: + fmtCount++; + seekNonWs(pattern, pos); + final int start = pos.getIndex(); + final int index = readArgumentIndex(pattern, next(pos)); + stripCustom.append(START_FE).append(index); + seekNonWs(pattern, pos); + Format format = null; + String formatDescription = null; + if (c[pos.getIndex()] == START_FMT) { + formatDescription = parseFormatDescription(pattern, + next(pos)); + format = getFormat(formatDescription); + if (format == null) { + stripCustom.append(START_FMT).append(formatDescription); + } + } + foundFormats.add(format); + foundDescriptions.add(format == null ? null : formatDescription); + Validate.isTrue(foundFormats.size() == fmtCount); + Validate.isTrue(foundDescriptions.size() == fmtCount); + if (c[pos.getIndex()] != END_FE) { + throw new IllegalArgumentException( + "Unreadable format element at position " + start); + } + //$FALL-THROUGH$ + default: + stripCustom.append(c[pos.getIndex()]); + next(pos); + } + } + super.applyPattern(stripCustom.toString()); + toPattern = insertFormats(super.toPattern(), foundDescriptions); + if (containsElements(foundFormats)) { + final Format[] origFormats = getFormats(); + // only loop over what we know we have, as MessageFormat on Java 1.3 + // seems to provide an extra format element: + int i = 0; + for (final Iterator it = foundFormats.iterator(); it.hasNext(); i++) { + final Format f = it.next(); + if (f != null) { + origFormats[i] = f; + } + } + super.setFormats(origFormats); + } + } + + /** + * Throws UnsupportedOperationException - see class Javadoc for details. + * + * @param formatElementIndex format element index + * @param newFormat the new format + * @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat + */ + @Override + public void setFormat(final int formatElementIndex, final Format newFormat) { + throw new UnsupportedOperationException(); + } + + /** + * Throws UnsupportedOperationException - see class Javadoc for details. + * + * @param argumentIndex argument index + * @param newFormat the new format + * @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat + */ + @Override + public void setFormatByArgumentIndex(final int argumentIndex, final Format newFormat) { + throw new UnsupportedOperationException(); + } + + /** + * Throws UnsupportedOperationException - see class Javadoc for details. + * + * @param newFormats new formats + * @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat + */ + @Override + public void setFormats(final Format[] newFormats) { + throw new UnsupportedOperationException(); + } + + /** + * Throws UnsupportedOperationException - see class Javadoc for details. + * + * @param newFormats new formats + * @throws UnsupportedOperationException always thrown since this isn't supported by ExtendMessageFormat + */ + @Override + public void setFormatsByArgumentIndex(final Format[] newFormats) { + throw new UnsupportedOperationException(); + } + + /** + * Check if this extended message format is equal to another object. + * + * @param obj the object to compare to + * @return true if this object equals the other, otherwise false + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj == null) { + return false; + } + if (!super.equals(obj)) { + return false; + } + if (ObjectUtils.notEqual(getClass(), obj.getClass())) { + return false; + } + final ExtendedMessageFormat rhs = (ExtendedMessageFormat)obj; + if (ObjectUtils.notEqual(toPattern, rhs.toPattern)) { + return false; + } + if (ObjectUtils.notEqual(registry, rhs.registry)) { + return false; + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int result = super.hashCode(); + result = HASH_SEED * result + Objects.hashCode(registry); + result = HASH_SEED * result + Objects.hashCode(toPattern); + return result; + } + + /** + * Get a custom format from a format description. + * + * @param desc String + * @return Format + */ + private Format getFormat(final String desc) { + if (registry != null) { + String name = desc; + String args = null; + final int i = desc.indexOf(START_FMT); + if (i > 0) { + name = desc.substring(0, i).trim(); + args = desc.substring(i + 1).trim(); + } + final FormatFactory factory = registry.get(name); + if (factory != null) { + return factory.getFormat(name, args, getLocale()); + } + } + return null; + } + + /** + * Read the argument index from the current format element + * + * @param pattern pattern to parse + * @param pos current parse position + * @return argument index + */ + private int readArgumentIndex(final String pattern, final ParsePosition pos) { + final int start = pos.getIndex(); + seekNonWs(pattern, pos); + final StringBuilder result = new StringBuilder(); + boolean error = false; + for (; !error && pos.getIndex() < pattern.length(); next(pos)) { + char c = pattern.charAt(pos.getIndex()); + if (Character.isWhitespace(c)) { + seekNonWs(pattern, pos); + c = pattern.charAt(pos.getIndex()); + if (c != START_FMT && c != END_FE) { + error = true; + continue; + } + } + if ((c == START_FMT || c == END_FE) && result.length() > 0) { + try { + return Integer.parseInt(result.toString()); + } catch (final NumberFormatException e) { // NOPMD + // we've already ensured only digits, so unless something + // outlandishly large was specified we should be okay. + } + } + error = !Character.isDigit(c); + result.append(c); + } + if (error) { + throw new IllegalArgumentException( + "Invalid format argument index at position " + start + ": " + + pattern.substring(start, pos.getIndex())); + } + throw new IllegalArgumentException( + "Unterminated format element at position " + start); + } + + /** + * Parse the format component of a format element. + * + * @param pattern string to parse + * @param pos current parse position + * @return Format description String + */ + private String parseFormatDescription(final String pattern, final ParsePosition pos) { + final int start = pos.getIndex(); + seekNonWs(pattern, pos); + final int text = pos.getIndex(); + int depth = 1; + for (; pos.getIndex() < pattern.length(); next(pos)) { + switch (pattern.charAt(pos.getIndex())) { + case START_FE: + depth++; + break; + case END_FE: + depth--; + if (depth == 0) { + return pattern.substring(text, pos.getIndex()); + } + break; + case QUOTE: + getQuotedString(pattern, pos); + break; + default: + break; + } + } + throw new IllegalArgumentException( + "Unterminated format element at position " + start); + } + + /** + * Insert formats back into the pattern for toPattern() support. + * + * @param pattern source + * @param customPatterns The custom patterns to re-insert, if any + * @return full pattern + */ + private String insertFormats(final String pattern, final ArrayList customPatterns) { + if (!containsElements(customPatterns)) { + return pattern; + } + final StringBuilder sb = new StringBuilder(pattern.length() * 2); + final ParsePosition pos = new ParsePosition(0); + int fe = -1; + int depth = 0; + while (pos.getIndex() < pattern.length()) { + final char c = pattern.charAt(pos.getIndex()); + switch (c) { + case QUOTE: + appendQuotedString(pattern, pos, sb); + break; + case START_FE: + depth++; + sb.append(START_FE).append(readArgumentIndex(pattern, next(pos))); + // do not look for custom patterns when they are embedded, e.g. in a choice + if (depth == 1) { + fe++; + final String customPattern = customPatterns.get(fe); + if (customPattern != null) { + sb.append(START_FMT).append(customPattern); + } + } + break; + case END_FE: + depth--; + //$FALL-THROUGH$ + default: + sb.append(c); + next(pos); + } + } + return sb.toString(); + } + + /** + * Consume whitespace from the current parse position. + * + * @param pattern String to read + * @param pos current position + */ + private void seekNonWs(final String pattern, final ParsePosition pos) { + int len = 0; + final char[] buffer = pattern.toCharArray(); + do { + len = StrMatcher.splitMatcher().isMatch(buffer, pos.getIndex()); + pos.setIndex(pos.getIndex() + len); + } while (len > 0 && pos.getIndex() < pattern.length()); + } + + /** + * Convenience method to advance parse position by 1 + * + * @param pos ParsePosition + * @return pos + */ + private ParsePosition next(final ParsePosition pos) { + pos.setIndex(pos.getIndex() + 1); + return pos; + } + + /** + * Consume a quoted string, adding it to appendTo if + * specified. + * + * @param pattern pattern to parse + * @param pos current parse position + * @param appendTo optional StringBuilder to append + * @return appendTo + */ + private StringBuilder appendQuotedString(final String pattern, final ParsePosition pos, + final StringBuilder appendTo) { + assert pattern.toCharArray()[pos.getIndex()] == QUOTE : + "Quoted string must start with quote character"; + + // handle quote character at the beginning of the string + if(appendTo != null) { + appendTo.append(QUOTE); + } + next(pos); + + final int start = pos.getIndex(); + final char[] c = pattern.toCharArray(); + final int lastHold = start; + for (int i = pos.getIndex(); i < pattern.length(); i++) { + switch (c[pos.getIndex()]) { + case QUOTE: + next(pos); + return appendTo == null ? null : appendTo.append(c, lastHold, + pos.getIndex() - lastHold); + default: + next(pos); + } + } + throw new IllegalArgumentException( + "Unterminated quoted string at position " + start); + } + + /** + * Consume quoted string only + * + * @param pattern pattern to parse + * @param pos current parse position + */ + private void getQuotedString(final String pattern, final ParsePosition pos) { + appendQuotedString(pattern, pos, null); + } + + /** + * Learn whether the specified Collection contains non-null elements. + * @param coll to check + * @return true if some Object was found, false otherwise. + */ + private boolean containsElements(final Collection coll) { + if (coll == null || coll.isEmpty()) { + return false; + } + for (final Object name : coll) { + if (name != null) { + return true; + } + } + return false; + } +} diff --git a/src/org/apache/commons/lang3/text/FormatFactory.java b/src/org/apache/commons/lang3/text/FormatFactory.java new file mode 100644 index 0000000..b6e3583 --- /dev/null +++ b/src/org/apache/commons/lang3/text/FormatFactory.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.text.Format; +import java.util.Locale; + +/** + * Format factory. + * + * @since 2.4 + * @deprecated as of 3.6, use commons-text + * + * FormatFactory instead + */ +@Deprecated +public interface FormatFactory { + + /** + * Create or retrieve a format instance. + * + * @param name The format type name + * @param arguments Arguments used to create the format instance. This allows the + * FormatFactory to implement the "format style" + * concept from java.text.MessageFormat. + * @param locale The locale, may be null + * @return The format instance + */ + Format getFormat(String name, String arguments, Locale locale); + +} diff --git a/src/org/apache/commons/lang3/text/FormattableUtils.java b/src/org/apache/commons/lang3/text/FormattableUtils.java new file mode 100644 index 0000000..9fdf6ec --- /dev/null +++ b/src/org/apache/commons/lang3/text/FormattableUtils.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import static java.util.FormattableFlags.LEFT_JUSTIFY; + +import java.util.Formattable; +import java.util.Formatter; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; + +/** + *

              Provides utilities for working with the {@code Formattable} interface.

              + * + *

              The {@link Formattable} interface provides basic control over formatting + * when using a {@code Formatter}. It is primarily concerned with numeric precision + * and padding, and is not designed to allow generalised alternate formats.

              + * + * @since Lang 3.0 + * @deprecated as of 3.6, use commons-text + * + * FormattableUtils instead + */ +@Deprecated +public class FormattableUtils { + + /** + * A format that simply outputs the value as a string. + */ + private static final String SIMPLEST_FORMAT = "%s"; + + /** + *

              {@code FormattableUtils} instances should NOT be constructed in + * standard programming. Instead, the methods of the class should be invoked + * statically.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public FormattableUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + * Get the default formatted representation of the specified + * {@code Formattable}. + * + * @param formattable the instance to convert to a string, not null + * @return the resulting string, not null + */ + public static String toString(final Formattable formattable) { + return String.format(SIMPLEST_FORMAT, formattable); + } + + /** + * Handles the common {@code Formattable} operations of truncate-pad-append, + * with no ellipsis on precision overflow, and padding width underflow with + * spaces. + * + * @param seq the string to handle, not null + * @param formatter the destination formatter, not null + * @param flags the flags for formatting, see {@code Formattable} + * @param width the width of the output, see {@code Formattable} + * @param precision the precision of the output, see {@code Formattable} + * @return the {@code formatter} instance, not null + */ + public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, + final int precision) { + return append(seq, formatter, flags, width, precision, ' ', null); + } + + /** + * Handles the common {@link Formattable} operations of truncate-pad-append, + * with no ellipsis on precision overflow. + * + * @param seq the string to handle, not null + * @param formatter the destination formatter, not null + * @param flags the flags for formatting, see {@code Formattable} + * @param width the width of the output, see {@code Formattable} + * @param precision the precision of the output, see {@code Formattable} + * @param padChar the pad character to use + * @return the {@code formatter} instance, not null + */ + public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, + final int precision, final char padChar) { + return append(seq, formatter, flags, width, precision, padChar, null); + } + + /** + * Handles the common {@link Formattable} operations of truncate-pad-append, + * padding width underflow with spaces. + * + * @param seq the string to handle, not null + * @param formatter the destination formatter, not null + * @param flags the flags for formatting, see {@code Formattable} + * @param width the width of the output, see {@code Formattable} + * @param precision the precision of the output, see {@code Formattable} + * @param ellipsis the ellipsis to use when precision dictates truncation, null or + * empty causes a hard truncation + * @return the {@code formatter} instance, not null + */ + public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, + final int precision, final CharSequence ellipsis) { + return append(seq, formatter, flags, width, precision, ' ', ellipsis); + } + + /** + * Handles the common {@link Formattable} operations of truncate-pad-append. + * + * @param seq the string to handle, not null + * @param formatter the destination formatter, not null + * @param flags the flags for formatting, see {@code Formattable} + * @param width the width of the output, see {@code Formattable} + * @param precision the precision of the output, see {@code Formattable} + * @param padChar the pad character to use + * @param ellipsis the ellipsis to use when precision dictates truncation, null or + * empty causes a hard truncation + * @return the {@code formatter} instance, not null + */ + public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width, + final int precision, final char padChar, final CharSequence ellipsis) { + Validate.isTrue(ellipsis == null || precision < 0 || ellipsis.length() <= precision, + "Specified ellipsis '%1$s' exceeds precision of %2$s", ellipsis, Integer.valueOf(precision)); + final StringBuilder buf = new StringBuilder(seq); + if (precision >= 0 && precision < seq.length()) { + final CharSequence _ellipsis = ObjectUtils.defaultIfNull(ellipsis, StringUtils.EMPTY); + buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString()); + } + final boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY; + for (int i = buf.length(); i < width; i++) { + buf.insert(leftJustify ? i : 0, padChar); + } + formatter.format(buf.toString()); + return formatter; + } + +} diff --git a/src/org/apache/commons/lang3/text/StrBuilder.java b/src/org/apache/commons/lang3/text/StrBuilder.java new file mode 100644 index 0000000..e7401f3 --- /dev/null +++ b/src/org/apache/commons/lang3/text/StrBuilder.java @@ -0,0 +1,3133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.io.IOException; +import java.io.Reader; +import java.io.Serializable; +import java.io.Writer; +import java.nio.CharBuffer; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.Builder; + +/** + * Builds a string from constituent parts providing a more flexible and powerful API + * than StringBuffer. + *

              + * The main differences from StringBuffer/StringBuilder are: + *

              + *
                + *
              • Not synchronized
              • + *
              • Not final
              • + *
              • Subclasses have direct access to character array
              • + *
              • Additional methods + *
                  + *
                • appendWithSeparators - adds an array of values, with a separator
                • + *
                • appendPadding - adds a length padding characters
                • + *
                • appendFixedLength - adds a fixed width field to the builder
                • + *
                • toCharArray/getChars - simpler ways to get a range of the character array
                • + *
                • delete - delete char or string
                • + *
                • replace - search and replace for a char or string
                • + *
                • leftString/rightString/midString - substring without exceptions
                • + *
                • contains - whether the builder contains a char or string
                • + *
                • size/clear/isEmpty - collections style API methods
                • + *
                + *
              • + *
              • Views + *
                  + *
                • asTokenizer - uses the internal buffer as the source of a StrTokenizer
                • + *
                • asReader - uses the internal buffer as the source of a Reader
                • + *
                • asWriter - allows a Writer to write directly to the internal buffer
                • + *
                + *
              • + *
              + *

              + * The aim has been to provide an API that mimics very closely what StringBuffer + * provides, but with additional methods. It should be noted that some edge cases, + * with invalid indices or null input, have been altered - see individual methods. + * The biggest of these changes is that by default, null will not output the text + * 'null'. This can be controlled by a property, {@link #setNullText(String)}. + *

              + * Prior to 3.0, this class implemented Cloneable but did not implement the + * clone method so could not be used. From 3.0 onwards it no longer implements + * the interface. + * + * @since 2.2 + * @deprecated as of 3.6, use commons-text + * + * StrBuilder instead + */ +@Deprecated +public class StrBuilder implements CharSequence, Appendable, Serializable, Builder { + + /** + * The extra capacity for new builders. + */ + static final int CAPACITY = 32; + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 7628716375283629643L; + + /** Internal data storage. */ + protected char[] buffer; // TODO make private? + /** Current size of the buffer. */ + protected int size; // TODO make private? + /** The new line. */ + private String newLine; + /** The null text. */ + private String nullText; + + //----------------------------------------------------------------------- + /** + * Constructor that creates an empty builder initial capacity 32 characters. + */ + public StrBuilder() { + this(CAPACITY); + } + + /** + * Constructor that creates an empty builder the specified initial capacity. + * + * @param initialCapacity the initial capacity, zero or less will be converted to 32 + */ + public StrBuilder(int initialCapacity) { + super(); + if (initialCapacity <= 0) { + initialCapacity = CAPACITY; + } + buffer = new char[initialCapacity]; + } + + /** + * Constructor that creates a builder from the string, allocating + * 32 extra characters for growth. + * + * @param str the string to copy, null treated as blank string + */ + public StrBuilder(final String str) { + super(); + if (str == null) { + buffer = new char[CAPACITY]; + } else { + buffer = new char[str.length() + CAPACITY]; + append(str); + } + } + + //----------------------------------------------------------------------- + /** + * Gets the text to be appended when a new line is added. + * + * @return the new line text, null means use system default + */ + public String getNewLineText() { + return newLine; + } + + /** + * Sets the text to be appended when a new line is added. + * + * @param newLine the new line text, null means use system default + * @return this, to enable chaining + */ + public StrBuilder setNewLineText(final String newLine) { + this.newLine = newLine; + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the text to be appended when null is added. + * + * @return the null text, null means no append + */ + public String getNullText() { + return nullText; + } + + /** + * Sets the text to be appended when null is added. + * + * @param nullText the null text, null means no append + * @return this, to enable chaining + */ + public StrBuilder setNullText(String nullText) { + if (nullText != null && nullText.isEmpty()) { + nullText = null; + } + this.nullText = nullText; + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the length of the string builder. + * + * @return the length + */ + @Override + public int length() { + return size; + } + + /** + * Updates the length of the builder by either dropping the last characters + * or adding filler of Unicode zero. + * + * @param length the length to set to, must be zero or positive + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the length is negative + */ + public StrBuilder setLength(final int length) { + if (length < 0) { + throw new StringIndexOutOfBoundsException(length); + } + if (length < size) { + size = length; + } else if (length > size) { + ensureCapacity(length); + final int oldEnd = size; + final int newEnd = length; + size = length; + for (int i = oldEnd; i < newEnd; i++) { + buffer[i] = '\0'; + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the current size of the internal character array buffer. + * + * @return the capacity + */ + public int capacity() { + return buffer.length; + } + + /** + * Checks the capacity and ensures that it is at least the size specified. + * + * @param capacity the capacity to ensure + * @return this, to enable chaining + */ + public StrBuilder ensureCapacity(final int capacity) { + if (capacity > buffer.length) { + final char[] old = buffer; + buffer = new char[capacity * 2]; + System.arraycopy(old, 0, buffer, 0, size); + } + return this; + } + + /** + * Minimizes the capacity to the actual length of the string. + * + * @return this, to enable chaining + */ + public StrBuilder minimizeCapacity() { + if (buffer.length > length()) { + final char[] old = buffer; + buffer = new char[length()]; + System.arraycopy(old, 0, buffer, 0, size); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the length of the string builder. + *

              + * This method is the same as {@link #length()} and is provided to match the + * API of Collections. + * + * @return the length + */ + public int size() { + return size; + } + + /** + * Checks is the string builder is empty (convenience Collections API style method). + *

              + * This method is the same as checking {@link #length()} and is provided to match the + * API of Collections. + * + * @return true if the size is 0. + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * Clears the string builder (convenience Collections API style method). + *

              + * This method does not reduce the size of the internal character buffer. + * To do that, call clear() followed by {@link #minimizeCapacity()}. + *

              + * This method is the same as {@link #setLength(int)} called with zero + * and is provided to match the API of Collections. + * + * @return this, to enable chaining + */ + public StrBuilder clear() { + size = 0; + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the character at the specified index. + * + * @see #setCharAt(int, char) + * @see #deleteCharAt(int) + * @param index the index to retrieve, must be valid + * @return the character at the index + * @throws IndexOutOfBoundsException if the index is invalid + */ + @Override + public char charAt(final int index) { + if (index < 0 || index >= length()) { + throw new StringIndexOutOfBoundsException(index); + } + return buffer[index]; + } + + /** + * Sets the character at the specified index. + * + * @see #charAt(int) + * @see #deleteCharAt(int) + * @param index the index to set + * @param ch the new character + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder setCharAt(final int index, final char ch) { + if (index < 0 || index >= length()) { + throw new StringIndexOutOfBoundsException(index); + } + buffer[index] = ch; + return this; + } + + /** + * Deletes the character at the specified index. + * + * @see #charAt(int) + * @see #setCharAt(int, char) + * @param index the index to delete + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder deleteCharAt(final int index) { + if (index < 0 || index >= size) { + throw new StringIndexOutOfBoundsException(index); + } + deleteImpl(index, index + 1, 1); + return this; + } + + //----------------------------------------------------------------------- + /** + * Copies the builder's character array into a new character array. + * + * @return a new array that represents the contents of the builder + */ + public char[] toCharArray() { + if (size == 0) { + return ArrayUtils.EMPTY_CHAR_ARRAY; + } + final char chars[] = new char[size]; + System.arraycopy(buffer, 0, chars, 0, size); + return chars; + } + + /** + * Copies part of the builder's character array into a new character array. + * + * @param startIndex the start index, inclusive, must be valid + * @param endIndex the end index, exclusive, must be valid except that + * if too large it is treated as end of string + * @return a new array that holds part of the contents of the builder + * @throws IndexOutOfBoundsException if startIndex is invalid, + * or if endIndex is invalid (but endIndex greater than size is valid) + */ + public char[] toCharArray(final int startIndex, int endIndex) { + endIndex = validateRange(startIndex, endIndex); + final int len = endIndex - startIndex; + if (len == 0) { + return ArrayUtils.EMPTY_CHAR_ARRAY; + } + final char chars[] = new char[len]; + System.arraycopy(buffer, startIndex, chars, 0, len); + return chars; + } + + /** + * Copies the character array into the specified array. + * + * @param destination the destination array, null will cause an array to be created + * @return the input array, unless that was null or too small + */ + public char[] getChars(char[] destination) { + final int len = length(); + if (destination == null || destination.length < len) { + destination = new char[len]; + } + System.arraycopy(buffer, 0, destination, 0, len); + return destination; + } + + /** + * Copies the character array into the specified array. + * + * @param startIndex first index to copy, inclusive, must be valid + * @param endIndex last index, exclusive, must be valid + * @param destination the destination array, must not be null or too small + * @param destinationIndex the index to start copying in destination + * @throws NullPointerException if the array is null + * @throws IndexOutOfBoundsException if any index is invalid + */ + public void getChars(final int startIndex, final int endIndex, final char destination[], final int destinationIndex) { + if (startIndex < 0) { + throw new StringIndexOutOfBoundsException(startIndex); + } + if (endIndex < 0 || endIndex > length()) { + throw new StringIndexOutOfBoundsException(endIndex); + } + if (startIndex > endIndex) { + throw new StringIndexOutOfBoundsException("end < start"); + } + System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex); + } + + //----------------------------------------------------------------------- + /** + * If possible, reads chars from the provided {@link Readable} directly into underlying + * character buffer without making extra copies. + * + * @param readable object to read from + * @return the number of characters read + * @throws IOException if an I/O error occurs + * + * @since 3.4 + * @see #appendTo(Appendable) + */ + public int readFrom(final Readable readable) throws IOException { + final int oldSize = size; + if (readable instanceof Reader) { + final Reader r = (Reader) readable; + ensureCapacity(size + 1); + int read; + while ((read = r.read(buffer, size, buffer.length - size)) != -1) { + size += read; + ensureCapacity(size + 1); + } + } else if (readable instanceof CharBuffer) { + final CharBuffer cb = (CharBuffer) readable; + final int remaining = cb.remaining(); + ensureCapacity(size + remaining); + cb.get(buffer, size, remaining); + size += remaining; + } else { + while (true) { + ensureCapacity(size + 1); + final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size); + final int read = readable.read(buf); + if (read == -1) { + break; + } + size += read; + } + } + return size - oldSize; + } + + //----------------------------------------------------------------------- + /** + * Appends the new line string to this string builder. + *

              + * The new line string can be altered using {@link #setNewLineText(String)}. + * This might be used to force the output to always use Unix line endings + * even when on Windows. + * + * @return this, to enable chaining + */ + public StrBuilder appendNewLine() { + if (newLine == null) { + append(System.lineSeparator()); + return this; + } + return append(newLine); + } + + /** + * Appends the text representing null to this string builder. + * + * @return this, to enable chaining + */ + public StrBuilder appendNull() { + if (nullText == null) { + return this; + } + return append(nullText); + } + + /** + * Appends an object to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param obj the object to append + * @return this, to enable chaining + */ + public StrBuilder append(final Object obj) { + if (obj == null) { + return appendNull(); + } + if (obj instanceof CharSequence) { + return append((CharSequence) obj); + } + return append(obj.toString()); + } + + /** + * Appends a CharSequence to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param seq the CharSequence to append + * @return this, to enable chaining + * @since 3.0 + */ + @Override + public StrBuilder append(final CharSequence seq) { + if (seq == null) { + return appendNull(); + } + if (seq instanceof StrBuilder) { + return append((StrBuilder) seq); + } + if (seq instanceof StringBuilder) { + return append((StringBuilder) seq); + } + if (seq instanceof StringBuffer) { + return append((StringBuffer) seq); + } + if (seq instanceof CharBuffer) { + return append((CharBuffer) seq); + } + return append(seq.toString()); + } + + /** + * Appends part of a CharSequence to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param seq the CharSequence to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 3.0 + */ + @Override + public StrBuilder append(final CharSequence seq, final int startIndex, final int length) { + if (seq == null) { + return appendNull(); + } + return append(seq.toString(), startIndex, length); + } + + /** + * Appends a string to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @return this, to enable chaining + */ + public StrBuilder append(final String str) { + if (str == null) { + return appendNull(); + } + final int strLen = str.length(); + if (strLen > 0) { + final int len = length(); + ensureCapacity(len + strLen); + str.getChars(0, strLen, buffer, len); + size += strLen; + } + return this; + } + + + /** + * Appends part of a string to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + */ + public StrBuilder append(final String str, final int startIndex, final int length) { + if (str == null) { + return appendNull(); + } + if (startIndex < 0 || startIndex > str.length()) { + throw new StringIndexOutOfBoundsException("startIndex must be valid"); + } + if (length < 0 || (startIndex + length) > str.length()) { + throw new StringIndexOutOfBoundsException("length must be valid"); + } + if (length > 0) { + final int len = length(); + ensureCapacity(len + length); + str.getChars(startIndex, startIndex + length, buffer, len); + size += length; + } + return this; + } + + /** + * Calls {@link String#format(String, Object...)} and appends the result. + * + * @param format the format string + * @param objs the objects to use in the format string + * @return {@code this} to enable chaining + * @see String#format(String, Object...) + * @since 3.2 + */ + public StrBuilder append(final String format, final Object... objs) { + return append(String.format(format, objs)); + } + + /** + * Appends the contents of a char buffer to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param buf the char buffer to append + * @return this, to enable chaining + * @since 3.4 + */ + public StrBuilder append(final CharBuffer buf) { + if (buf == null) { + return appendNull(); + } + if (buf.hasArray()) { + final int length = buf.remaining(); + final int len = length(); + ensureCapacity(len + length); + System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), buffer, len, length); + size += length; + } else { + append(buf.toString()); + } + return this; + } + + /** + * Appends the contents of a char buffer to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param buf the char buffer to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 3.4 + */ + public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) { + if (buf == null) { + return appendNull(); + } + if (buf.hasArray()) { + final int totalLength = buf.remaining(); + if (startIndex < 0 || startIndex > totalLength) { + throw new StringIndexOutOfBoundsException("startIndex must be valid"); + } + if (length < 0 || (startIndex + length) > totalLength) { + throw new StringIndexOutOfBoundsException("length must be valid"); + } + final int len = length(); + ensureCapacity(len + length); + System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length); + size += length; + } else { + append(buf.toString(), startIndex, length); + } + return this; + } + + /** + * Appends a string buffer to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string buffer to append + * @return this, to enable chaining + */ + public StrBuilder append(final StringBuffer str) { + if (str == null) { + return appendNull(); + } + final int strLen = str.length(); + if (strLen > 0) { + final int len = length(); + ensureCapacity(len + strLen); + str.getChars(0, strLen, buffer, len); + size += strLen; + } + return this; + } + + /** + * Appends part of a string buffer to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + */ + public StrBuilder append(final StringBuffer str, final int startIndex, final int length) { + if (str == null) { + return appendNull(); + } + if (startIndex < 0 || startIndex > str.length()) { + throw new StringIndexOutOfBoundsException("startIndex must be valid"); + } + if (length < 0 || (startIndex + length) > str.length()) { + throw new StringIndexOutOfBoundsException("length must be valid"); + } + if (length > 0) { + final int len = length(); + ensureCapacity(len + length); + str.getChars(startIndex, startIndex + length, buffer, len); + size += length; + } + return this; + } + + /** + * Appends a StringBuilder to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the StringBuilder to append + * @return this, to enable chaining + * @since 3.2 + */ + public StrBuilder append(final StringBuilder str) { + if (str == null) { + return appendNull(); + } + final int strLen = str.length(); + if (strLen > 0) { + final int len = length(); + ensureCapacity(len + strLen); + str.getChars(0, strLen, buffer, len); + size += strLen; + } + return this; + } + + /** + * Appends part of a StringBuilder to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the StringBuilder to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 3.2 + */ + public StrBuilder append(final StringBuilder str, final int startIndex, final int length) { + if (str == null) { + return appendNull(); + } + if (startIndex < 0 || startIndex > str.length()) { + throw new StringIndexOutOfBoundsException("startIndex must be valid"); + } + if (length < 0 || (startIndex + length) > str.length()) { + throw new StringIndexOutOfBoundsException("length must be valid"); + } + if (length > 0) { + final int len = length(); + ensureCapacity(len + length); + str.getChars(startIndex, startIndex + length, buffer, len); + size += length; + } + return this; + } + + /** + * Appends another string builder to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string builder to append + * @return this, to enable chaining + */ + public StrBuilder append(final StrBuilder str) { + if (str == null) { + return appendNull(); + } + final int strLen = str.length(); + if (strLen > 0) { + final int len = length(); + ensureCapacity(len + strLen); + System.arraycopy(str.buffer, 0, buffer, len, strLen); + size += strLen; + } + return this; + } + + /** + * Appends part of a string builder to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + */ + public StrBuilder append(final StrBuilder str, final int startIndex, final int length) { + if (str == null) { + return appendNull(); + } + if (startIndex < 0 || startIndex > str.length()) { + throw new StringIndexOutOfBoundsException("startIndex must be valid"); + } + if (length < 0 || (startIndex + length) > str.length()) { + throw new StringIndexOutOfBoundsException("length must be valid"); + } + if (length > 0) { + final int len = length(); + ensureCapacity(len + length); + str.getChars(startIndex, startIndex + length, buffer, len); + size += length; + } + return this; + } + + /** + * Appends a char array to the string builder. + * Appending null will call {@link #appendNull()}. + * + * @param chars the char array to append + * @return this, to enable chaining + */ + public StrBuilder append(final char[] chars) { + if (chars == null) { + return appendNull(); + } + final int strLen = chars.length; + if (strLen > 0) { + final int len = length(); + ensureCapacity(len + strLen); + System.arraycopy(chars, 0, buffer, len, strLen); + size += strLen; + } + return this; + } + + /** + * Appends a char array to the string builder. + * Appending null will call {@link #appendNull()}. + * + * @param chars the char array to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + */ + public StrBuilder append(final char[] chars, final int startIndex, final int length) { + if (chars == null) { + return appendNull(); + } + if (startIndex < 0 || startIndex > chars.length) { + throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length); + } + if (length < 0 || (startIndex + length) > chars.length) { + throw new StringIndexOutOfBoundsException("Invalid length: " + length); + } + if (length > 0) { + final int len = length(); + ensureCapacity(len + length); + System.arraycopy(chars, startIndex, buffer, len, length); + size += length; + } + return this; + } + + /** + * Appends a boolean value to the string builder. + * + * @param value the value to append + * @return this, to enable chaining + */ + public StrBuilder append(final boolean value) { + if (value) { + ensureCapacity(size + 4); + buffer[size++] = 't'; + buffer[size++] = 'r'; + buffer[size++] = 'u'; + buffer[size++] = 'e'; + } else { + ensureCapacity(size + 5); + buffer[size++] = 'f'; + buffer[size++] = 'a'; + buffer[size++] = 'l'; + buffer[size++] = 's'; + buffer[size++] = 'e'; + } + return this; + } + + /** + * Appends a char value to the string builder. + * + * @param ch the value to append + * @return this, to enable chaining + * @since 3.0 + */ + @Override + public StrBuilder append(final char ch) { + final int len = length(); + ensureCapacity(len + 1); + buffer[size++] = ch; + return this; + } + + /** + * Appends an int value to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + */ + public StrBuilder append(final int value) { + return append(String.valueOf(value)); + } + + /** + * Appends a long value to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + */ + public StrBuilder append(final long value) { + return append(String.valueOf(value)); + } + + /** + * Appends a float value to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + */ + public StrBuilder append(final float value) { + return append(String.valueOf(value)); + } + + /** + * Appends a double value to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + */ + public StrBuilder append(final double value) { + return append(String.valueOf(value)); + } + + //----------------------------------------------------------------------- + /** + * Appends an object followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param obj the object to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final Object obj) { + return append(obj).appendNewLine(); + } + + /** + * Appends a string followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final String str) { + return append(str).appendNewLine(); + } + + /** + * Appends part of a string followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final String str, final int startIndex, final int length) { + return append(str, startIndex, length).appendNewLine(); + } + + /** + * Calls {@link String#format(String, Object...)} and appends the result. + * + * @param format the format string + * @param objs the objects to use in the format string + * @return {@code this} to enable chaining + * @see String#format(String, Object...) + * @since 3.2 + */ + public StrBuilder appendln(final String format, final Object... objs) { + return append(format, objs).appendNewLine(); + } + + /** + * Appends a string buffer followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string buffer to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final StringBuffer str) { + return append(str).appendNewLine(); + } + + /** + * Appends a string builder followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string builder to append + * @return this, to enable chaining + * @since 3.2 + */ + public StrBuilder appendln(final StringBuilder str) { + return append(str).appendNewLine(); + } + + /** + * Appends part of a string builder followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string builder to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 3.2 + */ + public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) { + return append(str, startIndex, length).appendNewLine(); + } + + /** + * Appends part of a string buffer followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) { + return append(str, startIndex, length).appendNewLine(); + } + + /** + * Appends another string builder followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string builder to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final StrBuilder str) { + return append(str).appendNewLine(); + } + + /** + * Appends part of a string builder followed by a new line to this string builder. + * Appending null will call {@link #appendNull()}. + * + * @param str the string to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) { + return append(str, startIndex, length).appendNewLine(); + } + + /** + * Appends a char array followed by a new line to the string builder. + * Appending null will call {@link #appendNull()}. + * + * @param chars the char array to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final char[] chars) { + return append(chars).appendNewLine(); + } + + /** + * Appends a char array followed by a new line to the string builder. + * Appending null will call {@link #appendNull()}. + * + * @param chars the char array to append + * @param startIndex the start index, inclusive, must be valid + * @param length the length to append, must be valid + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final char[] chars, final int startIndex, final int length) { + return append(chars, startIndex, length).appendNewLine(); + } + + /** + * Appends a boolean value followed by a new line to the string builder. + * + * @param value the value to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final boolean value) { + return append(value).appendNewLine(); + } + + /** + * Appends a char value followed by a new line to the string builder. + * + * @param ch the value to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final char ch) { + return append(ch).appendNewLine(); + } + + /** + * Appends an int value followed by a new line to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final int value) { + return append(value).appendNewLine(); + } + + /** + * Appends a long value followed by a new line to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final long value) { + return append(value).appendNewLine(); + } + + /** + * Appends a float value followed by a new line to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final float value) { + return append(value).appendNewLine(); + } + + /** + * Appends a double value followed by a new line to the string builder using String.valueOf. + * + * @param value the value to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendln(final double value) { + return append(value).appendNewLine(); + } + + //----------------------------------------------------------------------- + /** + * Appends each item in an array to the builder without any separators. + * Appending a null array will have no effect. + * Each object is appended using {@link #append(Object)}. + * + * @param the element type + * @param array the array to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) { + /* + * @SuppressWarnings used to hide warning about vararg usage. We cannot + * use @SafeVarargs, since this method is not final. Using @SupressWarnings + * is fine, because it isn't inherited by subclasses, so each subclass must + * vouch for itself whether its use of 'array' is safe. + */ + if (array != null && array.length > 0) { + for (final Object element : array) { + append(element); + } + } + return this; + } + + /** + * Appends each item in an iterable to the builder without any separators. + * Appending a null iterable will have no effect. + * Each object is appended using {@link #append(Object)}. + * + * @param iterable the iterable to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendAll(final Iterable iterable) { + if (iterable != null) { + for (final Object o : iterable) { + append(o); + } + } + return this; + } + + /** + * Appends each item in an iterator to the builder without any separators. + * Appending a null iterator will have no effect. + * Each object is appended using {@link #append(Object)}. + * + * @param it the iterator to append + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendAll(final Iterator it) { + if (it != null) { + while (it.hasNext()) { + append(it.next()); + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Appends an array placing separators between each value, but + * not before the first or after the last. + * Appending a null array will have no effect. + * Each object is appended using {@link #append(Object)}. + * + * @param array the array to append + * @param separator the separator to use, null means no separator + * @return this, to enable chaining + */ + public StrBuilder appendWithSeparators(final Object[] array, final String separator) { + if (array != null && array.length > 0) { + final String sep = Objects.toString(separator, ""); + append(array[0]); + for (int i = 1; i < array.length; i++) { + append(sep); + append(array[i]); + } + } + return this; + } + + /** + * Appends an iterable placing separators between each value, but + * not before the first or after the last. + * Appending a null iterable will have no effect. + * Each object is appended using {@link #append(Object)}. + * + * @param iterable the iterable to append + * @param separator the separator to use, null means no separator + * @return this, to enable chaining + */ + public StrBuilder appendWithSeparators(final Iterable iterable, final String separator) { + if (iterable != null) { + final String sep = Objects.toString(separator, ""); + final Iterator it = iterable.iterator(); + while (it.hasNext()) { + append(it.next()); + if (it.hasNext()) { + append(sep); + } + } + } + return this; + } + + /** + * Appends an iterator placing separators between each value, but + * not before the first or after the last. + * Appending a null iterator will have no effect. + * Each object is appended using {@link #append(Object)}. + * + * @param it the iterator to append + * @param separator the separator to use, null means no separator + * @return this, to enable chaining + */ + public StrBuilder appendWithSeparators(final Iterator it, final String separator) { + if (it != null) { + final String sep = Objects.toString(separator, ""); + while (it.hasNext()) { + append(it.next()); + if (it.hasNext()) { + append(sep); + } + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Appends a separator if the builder is currently non-empty. + * Appending a null separator will have no effect. + * The separator is appended using {@link #append(String)}. + *

              + * This method is useful for adding a separator each time around the + * loop except the first. + *

              +     * for (Iterator it = list.iterator(); it.hasNext(); ) {
              +     *   appendSeparator(",");
              +     *   append(it.next());
              +     * }
              +     * 
              + * Note that for this simple example, you should use + * {@link #appendWithSeparators(Iterable, String)}. + * + * @param separator the separator to use, null means no separator + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendSeparator(final String separator) { + return appendSeparator(separator, null); + } + + /** + * Appends one of both separators to the StrBuilder. + * If the builder is currently empty it will append the defaultIfEmpty-separator + * Otherwise it will append the standard-separator + * + * Appending a null separator will have no effect. + * The separator is appended using {@link #append(String)}. + *

              + * This method is for example useful for constructing queries + *

              +     * StrBuilder whereClause = new StrBuilder();
              +     * if(searchCommand.getPriority() != null) {
              +     *  whereClause.appendSeparator(" and", " where");
              +     *  whereClause.append(" priority = ?")
              +     * }
              +     * if(searchCommand.getComponent() != null) {
              +     *  whereClause.appendSeparator(" and", " where");
              +     *  whereClause.append(" component = ?")
              +     * }
              +     * selectClause.append(whereClause)
              +     * 
              + * + * @param standard the separator if builder is not empty, null means no separator + * @param defaultIfEmpty the separator if builder is empty, null means no separator + * @return this, to enable chaining + * @since 2.5 + */ + public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) { + final String str = isEmpty() ? defaultIfEmpty : standard; + if (str != null) { + append(str); + } + return this; + } + + /** + * Appends a separator if the builder is currently non-empty. + * The separator is appended using {@link #append(char)}. + *

              + * This method is useful for adding a separator each time around the + * loop except the first. + *

              +     * for (Iterator it = list.iterator(); it.hasNext(); ) {
              +     *   appendSeparator(',');
              +     *   append(it.next());
              +     * }
              +     * 
              + * Note that for this simple example, you should use + * {@link #appendWithSeparators(Iterable, String)}. + * + * @param separator the separator to use + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendSeparator(final char separator) { + if (size() > 0) { + append(separator); + } + return this; + } + + /** + * Append one of both separators to the builder + * If the builder is currently empty it will append the defaultIfEmpty-separator + * Otherwise it will append the standard-separator + * + * The separator is appended using {@link #append(char)}. + * @param standard the separator if builder is not empty + * @param defaultIfEmpty the separator if builder is empty + * @return this, to enable chaining + * @since 2.5 + */ + public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) { + if (size() > 0) { + append(standard); + } else { + append(defaultIfEmpty); + } + return this; + } + /** + * Appends a separator to the builder if the loop index is greater than zero. + * Appending a null separator will have no effect. + * The separator is appended using {@link #append(String)}. + *

              + * This method is useful for adding a separator each time around the + * loop except the first. + *

              + *
              +     * for (int i = 0; i < list.size(); i++) {
              +     *   appendSeparator(",", i);
              +     *   append(list.get(i));
              +     * }
              +     * 
              + * Note that for this simple example, you should use + * {@link #appendWithSeparators(Iterable, String)}. + * + * @param separator the separator to use, null means no separator + * @param loopIndex the loop index + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendSeparator(final String separator, final int loopIndex) { + if (separator != null && loopIndex > 0) { + append(separator); + } + return this; + } + + /** + * Appends a separator to the builder if the loop index is greater than zero. + * The separator is appended using {@link #append(char)}. + *

              + * This method is useful for adding a separator each time around the + * loop except the first. + *

              + *
              +     * for (int i = 0; i < list.size(); i++) {
              +     *   appendSeparator(",", i);
              +     *   append(list.get(i));
              +     * }
              +     * 
              + * Note that for this simple example, you should use + * {@link #appendWithSeparators(Iterable, String)}. + * + * @param separator the separator to use + * @param loopIndex the loop index + * @return this, to enable chaining + * @since 2.3 + */ + public StrBuilder appendSeparator(final char separator, final int loopIndex) { + if (loopIndex > 0) { + append(separator); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Appends the pad character to the builder the specified number of times. + * + * @param length the length to append, negative means no append + * @param padChar the character to append + * @return this, to enable chaining + */ + public StrBuilder appendPadding(final int length, final char padChar) { + if (length >= 0) { + ensureCapacity(size + length); + for (int i = 0; i < length; i++) { + buffer[size++] = padChar; + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Appends an object to the builder padding on the left to a fixed width. + * The toString of the object is used. + * If the object is larger than the length, the left hand side is lost. + * If the object is null, the null text value is used. + * + * @param obj the object to append, null uses null text + * @param width the fixed field width, zero or negative has no effect + * @param padChar the pad character to use + * @return this, to enable chaining + */ + public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) { + if (width > 0) { + ensureCapacity(size + width); + String str = (obj == null ? getNullText() : obj.toString()); + if (str == null) { + str = StringUtils.EMPTY; + } + final int strLen = str.length(); + if (strLen >= width) { + str.getChars(strLen - width, strLen, buffer, size); + } else { + final int padLen = width - strLen; + for (int i = 0; i < padLen; i++) { + buffer[size + i] = padChar; + } + str.getChars(0, strLen, buffer, size + padLen); + } + size += width; + } + return this; + } + + /** + * Appends an object to the builder padding on the left to a fixed width. + * The String.valueOf of the int value is used. + * If the formatted value is larger than the length, the left hand side is lost. + * + * @param value the value to append + * @param width the fixed field width, zero or negative has no effect + * @param padChar the pad character to use + * @return this, to enable chaining + */ + public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) { + return appendFixedWidthPadLeft(String.valueOf(value), width, padChar); + } + + /** + * Appends an object to the builder padding on the right to a fixed length. + * The toString of the object is used. + * If the object is larger than the length, the right hand side is lost. + * If the object is null, null text value is used. + * + * @param obj the object to append, null uses null text + * @param width the fixed field width, zero or negative has no effect + * @param padChar the pad character to use + * @return this, to enable chaining + */ + public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) { + if (width > 0) { + ensureCapacity(size + width); + String str = (obj == null ? getNullText() : obj.toString()); + if (str == null) { + str = StringUtils.EMPTY; + } + final int strLen = str.length(); + if (strLen >= width) { + str.getChars(0, width, buffer, size); + } else { + final int padLen = width - strLen; + str.getChars(0, strLen, buffer, size); + for (int i = 0; i < padLen; i++) { + buffer[size + strLen + i] = padChar; + } + } + size += width; + } + return this; + } + + /** + * Appends an object to the builder padding on the right to a fixed length. + * The String.valueOf of the int value is used. + * If the object is larger than the length, the right hand side is lost. + * + * @param value the value to append + * @param width the fixed field width, zero or negative has no effect + * @param padChar the pad character to use + * @return this, to enable chaining + */ + public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) { + return appendFixedWidthPadRight(String.valueOf(value), width, padChar); + } + + //----------------------------------------------------------------------- + /** + * Inserts the string representation of an object into this builder. + * Inserting null will use the stored null text value. + * + * @param index the index to add at, must be valid + * @param obj the object to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, final Object obj) { + if (obj == null) { + return insert(index, nullText); + } + return insert(index, obj.toString()); + } + + /** + * Inserts the string into this builder. + * Inserting null will use the stored null text value. + * + * @param index the index to add at, must be valid + * @param str the string to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, String str) { + validateIndex(index); + if (str == null) { + str = nullText; + } + if (str != null) { + final int strLen = str.length(); + if (strLen > 0) { + final int newSize = size + strLen; + ensureCapacity(newSize); + System.arraycopy(buffer, index, buffer, index + strLen, size - index); + size = newSize; + str.getChars(0, strLen, buffer, index); + } + } + return this; + } + + /** + * Inserts the character array into this builder. + * Inserting null will use the stored null text value. + * + * @param index the index to add at, must be valid + * @param chars the char array to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, final char chars[]) { + validateIndex(index); + if (chars == null) { + return insert(index, nullText); + } + final int len = chars.length; + if (len > 0) { + ensureCapacity(size + len); + System.arraycopy(buffer, index, buffer, index + len, size - index); + System.arraycopy(chars, 0, buffer, index, len); + size += len; + } + return this; + } + + /** + * Inserts part of the character array into this builder. + * Inserting null will use the stored null text value. + * + * @param index the index to add at, must be valid + * @param chars the char array to insert + * @param offset the offset into the character array to start at, must be valid + * @param length the length of the character array part to copy, must be positive + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if any index is invalid + */ + public StrBuilder insert(final int index, final char chars[], final int offset, final int length) { + validateIndex(index); + if (chars == null) { + return insert(index, nullText); + } + if (offset < 0 || offset > chars.length) { + throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); + } + if (length < 0 || offset + length > chars.length) { + throw new StringIndexOutOfBoundsException("Invalid length: " + length); + } + if (length > 0) { + ensureCapacity(size + length); + System.arraycopy(buffer, index, buffer, index + length, size - index); + System.arraycopy(chars, offset, buffer, index, length); + size += length; + } + return this; + } + + /** + * Inserts the value into this builder. + * + * @param index the index to add at, must be valid + * @param value the value to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(int index, final boolean value) { + validateIndex(index); + if (value) { + ensureCapacity(size + 4); + System.arraycopy(buffer, index, buffer, index + 4, size - index); + buffer[index++] = 't'; + buffer[index++] = 'r'; + buffer[index++] = 'u'; + buffer[index] = 'e'; + size += 4; + } else { + ensureCapacity(size + 5); + System.arraycopy(buffer, index, buffer, index + 5, size - index); + buffer[index++] = 'f'; + buffer[index++] = 'a'; + buffer[index++] = 'l'; + buffer[index++] = 's'; + buffer[index] = 'e'; + size += 5; + } + return this; + } + + /** + * Inserts the value into this builder. + * + * @param index the index to add at, must be valid + * @param value the value to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, final char value) { + validateIndex(index); + ensureCapacity(size + 1); + System.arraycopy(buffer, index, buffer, index + 1, size - index); + buffer[index] = value; + size++; + return this; + } + + /** + * Inserts the value into this builder. + * + * @param index the index to add at, must be valid + * @param value the value to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, final int value) { + return insert(index, String.valueOf(value)); + } + + /** + * Inserts the value into this builder. + * + * @param index the index to add at, must be valid + * @param value the value to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, final long value) { + return insert(index, String.valueOf(value)); + } + + /** + * Inserts the value into this builder. + * + * @param index the index to add at, must be valid + * @param value the value to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, final float value) { + return insert(index, String.valueOf(value)); + } + + /** + * Inserts the value into this builder. + * + * @param index the index to add at, must be valid + * @param value the value to insert + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder insert(final int index, final double value) { + return insert(index, String.valueOf(value)); + } + + //----------------------------------------------------------------------- + /** + * Internal method to delete a range without validation. + * + * @param startIndex the start index, must be valid + * @param endIndex the end index (exclusive), must be valid + * @param len the length, must be valid + * @throws IndexOutOfBoundsException if any index is invalid + */ + private void deleteImpl(final int startIndex, final int endIndex, final int len) { + System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); + size -= len; + } + + /** + * Deletes the characters between the two specified indices. + * + * @param startIndex the start index, inclusive, must be valid + * @param endIndex the end index, exclusive, must be valid except + * that if too large it is treated as end of string + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder delete(final int startIndex, int endIndex) { + endIndex = validateRange(startIndex, endIndex); + final int len = endIndex - startIndex; + if (len > 0) { + deleteImpl(startIndex, endIndex, len); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Deletes the character wherever it occurs in the builder. + * + * @param ch the character to delete + * @return this, to enable chaining + */ + public StrBuilder deleteAll(final char ch) { + for (int i = 0; i < size; i++) { + if (buffer[i] == ch) { + final int start = i; + while (++i < size) { + if (buffer[i] != ch) { + break; + } + } + final int len = i - start; + deleteImpl(start, i, len); + i -= len; + } + } + return this; + } + + /** + * Deletes the character wherever it occurs in the builder. + * + * @param ch the character to delete + * @return this, to enable chaining + */ + public StrBuilder deleteFirst(final char ch) { + for (int i = 0; i < size; i++) { + if (buffer[i] == ch) { + deleteImpl(i, i + 1, 1); + break; + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Deletes the string wherever it occurs in the builder. + * + * @param str the string to delete, null causes no action + * @return this, to enable chaining + */ + public StrBuilder deleteAll(final String str) { + final int len = (str == null ? 0 : str.length()); + if (len > 0) { + int index = indexOf(str, 0); + while (index >= 0) { + deleteImpl(index, index + len, len); + index = indexOf(str, index); + } + } + return this; + } + + /** + * Deletes the string wherever it occurs in the builder. + * + * @param str the string to delete, null causes no action + * @return this, to enable chaining + */ + public StrBuilder deleteFirst(final String str) { + final int len = (str == null ? 0 : str.length()); + if (len > 0) { + final int index = indexOf(str, 0); + if (index >= 0) { + deleteImpl(index, index + len, len); + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Deletes all parts of the builder that the matcher matches. + *

              + * Matchers can be used to perform advanced deletion behaviour. + * For example you could write a matcher to delete all occurrences + * where the character 'a' is followed by a number. + * + * @param matcher the matcher to use to find the deletion, null causes no action + * @return this, to enable chaining + */ + public StrBuilder deleteAll(final StrMatcher matcher) { + return replace(matcher, null, 0, size, -1); + } + + /** + * Deletes the first match within the builder using the specified matcher. + *

              + * Matchers can be used to perform advanced deletion behaviour. + * For example you could write a matcher to delete + * where the character 'a' is followed by a number. + * + * @param matcher the matcher to use to find the deletion, null causes no action + * @return this, to enable chaining + */ + public StrBuilder deleteFirst(final StrMatcher matcher) { + return replace(matcher, null, 0, size, 1); + } + + //----------------------------------------------------------------------- + /** + * Internal method to delete a range without validation. + * + * @param startIndex the start index, must be valid + * @param endIndex the end index (exclusive), must be valid + * @param removeLen the length to remove (endIndex - startIndex), must be valid + * @param insertStr the string to replace with, null means delete range + * @param insertLen the length of the insert string, must be valid + * @throws IndexOutOfBoundsException if any index is invalid + */ + private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) { + final int newSize = size - removeLen + insertLen; + if (insertLen != removeLen) { + ensureCapacity(newSize); + System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); + size = newSize; + } + if (insertLen > 0) { + insertStr.getChars(0, insertLen, buffer, startIndex); + } + } + + /** + * Replaces a portion of the string builder with another string. + * The length of the inserted string does not have to match the removed length. + * + * @param startIndex the start index, inclusive, must be valid + * @param endIndex the end index, exclusive, must be valid except + * that if too large it is treated as end of string + * @param replaceStr the string to replace with, null means delete range + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if the index is invalid + */ + public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) { + endIndex = validateRange(startIndex, endIndex); + final int insertLen = (replaceStr == null ? 0 : replaceStr.length()); + replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); + return this; + } + + //----------------------------------------------------------------------- + /** + * Replaces the search character with the replace character + * throughout the builder. + * + * @param search the search character + * @param replace the replace character + * @return this, to enable chaining + */ + public StrBuilder replaceAll(final char search, final char replace) { + if (search != replace) { + for (int i = 0; i < size; i++) { + if (buffer[i] == search) { + buffer[i] = replace; + } + } + } + return this; + } + + /** + * Replaces the first instance of the search character with the + * replace character in the builder. + * + * @param search the search character + * @param replace the replace character + * @return this, to enable chaining + */ + public StrBuilder replaceFirst(final char search, final char replace) { + if (search != replace) { + for (int i = 0; i < size; i++) { + if (buffer[i] == search) { + buffer[i] = replace; + break; + } + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Replaces the search string with the replace string throughout the builder. + * + * @param searchStr the search string, null causes no action to occur + * @param replaceStr the replace string, null is equivalent to an empty string + * @return this, to enable chaining + */ + public StrBuilder replaceAll(final String searchStr, final String replaceStr) { + final int searchLen = (searchStr == null ? 0 : searchStr.length()); + if (searchLen > 0) { + final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); + int index = indexOf(searchStr, 0); + while (index >= 0) { + replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); + index = indexOf(searchStr, index + replaceLen); + } + } + return this; + } + + /** + * Replaces the first instance of the search string with the replace string. + * + * @param searchStr the search string, null causes no action to occur + * @param replaceStr the replace string, null is equivalent to an empty string + * @return this, to enable chaining + */ + public StrBuilder replaceFirst(final String searchStr, final String replaceStr) { + final int searchLen = (searchStr == null ? 0 : searchStr.length()); + if (searchLen > 0) { + final int index = indexOf(searchStr, 0); + if (index >= 0) { + final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); + replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Replaces all matches within the builder with the replace string. + *

              + * Matchers can be used to perform advanced replace behaviour. + * For example you could write a matcher to replace all occurrences + * where the character 'a' is followed by a number. + * + * @param matcher the matcher to use to find the deletion, null causes no action + * @param replaceStr the replace string, null is equivalent to an empty string + * @return this, to enable chaining + */ + public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) { + return replace(matcher, replaceStr, 0, size, -1); + } + + /** + * Replaces the first match within the builder with the replace string. + *

              + * Matchers can be used to perform advanced replace behaviour. + * For example you could write a matcher to replace + * where the character 'a' is followed by a number. + * + * @param matcher the matcher to use to find the deletion, null causes no action + * @param replaceStr the replace string, null is equivalent to an empty string + * @return this, to enable chaining + */ + public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) { + return replace(matcher, replaceStr, 0, size, 1); + } + + // ----------------------------------------------------------------------- + /** + * Advanced search and replaces within the builder using a matcher. + *

              + * Matchers can be used to perform advanced behaviour. + * For example you could write a matcher to delete all occurrences + * where the character 'a' is followed by a number. + * + * @param matcher the matcher to use to find the deletion, null causes no action + * @param replaceStr the string to replace the match with, null is a delete + * @param startIndex the start index, inclusive, must be valid + * @param endIndex the end index, exclusive, must be valid except + * that if too large it is treated as end of string + * @param replaceCount the number of times to replace, -1 for replace all + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if start index is invalid + */ + public StrBuilder replace( + final StrMatcher matcher, final String replaceStr, + final int startIndex, int endIndex, final int replaceCount) { + endIndex = validateRange(startIndex, endIndex); + return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); + } + + /** + * Replaces within the builder using a matcher. + *

              + * Matchers can be used to perform advanced behaviour. + * For example you could write a matcher to delete all occurrences + * where the character 'a' is followed by a number. + * + * @param matcher the matcher to use to find the deletion, null causes no action + * @param replaceStr the string to replace the match with, null is a delete + * @param from the start index, must be valid + * @param to the end index (exclusive), must be valid + * @param replaceCount the number of times to replace, -1 for replace all + * @return this, to enable chaining + * @throws IndexOutOfBoundsException if any index is invalid + */ + private StrBuilder replaceImpl( + final StrMatcher matcher, final String replaceStr, + final int from, int to, int replaceCount) { + if (matcher == null || size == 0) { + return this; + } + final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); + for (int i = from; i < to && replaceCount != 0; i++) { + final char[] buf = buffer; + final int removeLen = matcher.isMatch(buf, i, from, to); + if (removeLen > 0) { + replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); + to = to - removeLen + replaceLen; + i = i + replaceLen - 1; + if (replaceCount > 0) { + replaceCount--; + } + } + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Reverses the string builder placing each character in the opposite index. + * + * @return this, to enable chaining + */ + public StrBuilder reverse() { + if (size == 0) { + return this; + } + + final int half = size / 2; + final char[] buf = buffer; + for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++,rightIdx--) { + final char swap = buf[leftIdx]; + buf[leftIdx] = buf[rightIdx]; + buf[rightIdx] = swap; + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Trims the builder by removing characters less than or equal to a space + * from the beginning and end. + * + * @return this, to enable chaining + */ + public StrBuilder trim() { + if (size == 0) { + return this; + } + int len = size; + final char[] buf = buffer; + int pos = 0; + while (pos < len && buf[pos] <= ' ') { + pos++; + } + while (pos < len && buf[len - 1] <= ' ') { + len--; + } + if (len < size) { + delete(len, size); + } + if (pos > 0) { + delete(0, pos); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Checks whether this builder starts with the specified string. + *

              + * Note that this method handles null input quietly, unlike String. + * + * @param str the string to search for, null returns false + * @return true if the builder starts with the string + */ + public boolean startsWith(final String str) { + if (str == null) { + return false; + } + final int len = str.length(); + if (len == 0) { + return true; + } + if (len > size) { + return false; + } + for (int i = 0; i < len; i++) { + if (buffer[i] != str.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Checks whether this builder ends with the specified string. + *

              + * Note that this method handles null input quietly, unlike String. + * + * @param str the string to search for, null returns false + * @return true if the builder ends with the string + */ + public boolean endsWith(final String str) { + if (str == null) { + return false; + } + final int len = str.length(); + if (len == 0) { + return true; + } + if (len > size) { + return false; + } + int pos = size - len; + for (int i = 0; i < len; i++,pos++) { + if (buffer[pos] != str.charAt(i)) { + return false; + } + } + return true; + } + + //----------------------------------------------------------------------- + /** + * {@inheritDoc} + * @since 3.0 + */ + @Override + public CharSequence subSequence(final int startIndex, final int endIndex) { + if (startIndex < 0) { + throw new StringIndexOutOfBoundsException(startIndex); + } + if (endIndex > size) { + throw new StringIndexOutOfBoundsException(endIndex); + } + if (startIndex > endIndex) { + throw new StringIndexOutOfBoundsException(endIndex - startIndex); + } + return substring(startIndex, endIndex); + } + + /** + * Extracts a portion of this string builder as a string. + * + * @param start the start index, inclusive, must be valid + * @return the new string + * @throws IndexOutOfBoundsException if the index is invalid + */ + public String substring(final int start) { + return substring(start, size); + } + + /** + * Extracts a portion of this string builder as a string. + *

              + * Note: This method treats an endIndex greater than the length of the + * builder as equal to the length of the builder, and continues + * without error, unlike StringBuffer or String. + * + * @param startIndex the start index, inclusive, must be valid + * @param endIndex the end index, exclusive, must be valid except + * that if too large it is treated as end of string + * @return the new string + * @throws IndexOutOfBoundsException if the index is invalid + */ + public String substring(final int startIndex, int endIndex) { + endIndex = validateRange(startIndex, endIndex); + return new String(buffer, startIndex, endIndex - startIndex); + } + + /** + * Extracts the leftmost characters from the string builder without + * throwing an exception. + *

              + * This method extracts the left length characters from + * the builder. If this many characters are not available, the whole + * builder is returned. Thus the returned string may be shorter than the + * length requested. + * + * @param length the number of characters to extract, negative returns empty string + * @return the new string + */ + public String leftString(final int length) { + if (length <= 0) { + return StringUtils.EMPTY; + } else if (length >= size) { + return new String(buffer, 0, size); + } else { + return new String(buffer, 0, length); + } + } + + /** + * Extracts the rightmost characters from the string builder without + * throwing an exception. + *

              + * This method extracts the right length characters from + * the builder. If this many characters are not available, the whole + * builder is returned. Thus the returned string may be shorter than the + * length requested. + * + * @param length the number of characters to extract, negative returns empty string + * @return the new string + */ + public String rightString(final int length) { + if (length <= 0) { + return StringUtils.EMPTY; + } else if (length >= size) { + return new String(buffer, 0, size); + } else { + return new String(buffer, size - length, length); + } + } + + /** + * Extracts some characters from the middle of the string builder without + * throwing an exception. + *

              + * This method extracts length characters from the builder + * at the specified index. + * If the index is negative it is treated as zero. + * If the index is greater than the builder size, it is treated as the builder size. + * If the length is negative, the empty string is returned. + * If insufficient characters are available in the builder, as much as possible is returned. + * Thus the returned string may be shorter than the length requested. + * + * @param index the index to start at, negative means zero + * @param length the number of characters to extract, negative returns empty string + * @return the new string + */ + public String midString(int index, final int length) { + if (index < 0) { + index = 0; + } + if (length <= 0 || index >= size) { + return StringUtils.EMPTY; + } + if (size <= index + length) { + return new String(buffer, index, size - index); + } + return new String(buffer, index, length); + } + + //----------------------------------------------------------------------- + /** + * Checks if the string builder contains the specified char. + * + * @param ch the character to find + * @return true if the builder contains the character + */ + public boolean contains(final char ch) { + final char[] thisBuf = buffer; + for (int i = 0; i < this.size; i++) { + if (thisBuf[i] == ch) { + return true; + } + } + return false; + } + + /** + * Checks if the string builder contains the specified string. + * + * @param str the string to find + * @return true if the builder contains the string + */ + public boolean contains(final String str) { + return indexOf(str, 0) >= 0; + } + + /** + * Checks if the string builder contains a string matched using the + * specified matcher. + *

              + * Matchers can be used to perform advanced searching behaviour. + * For example you could write a matcher to search for the character + * 'a' followed by a number. + * + * @param matcher the matcher to use, null returns -1 + * @return true if the matcher finds a match in the builder + */ + public boolean contains(final StrMatcher matcher) { + return indexOf(matcher, 0) >= 0; + } + + //----------------------------------------------------------------------- + /** + * Searches the string builder to find the first reference to the specified char. + * + * @param ch the character to find + * @return the first index of the character, or -1 if not found + */ + public int indexOf(final char ch) { + return indexOf(ch, 0); + } + + /** + * Searches the string builder to find the first reference to the specified char. + * + * @param ch the character to find + * @param startIndex the index to start at, invalid index rounded to edge + * @return the first index of the character, or -1 if not found + */ + public int indexOf(final char ch, int startIndex) { + startIndex = (startIndex < 0 ? 0 : startIndex); + if (startIndex >= size) { + return -1; + } + final char[] thisBuf = buffer; + for (int i = startIndex; i < size; i++) { + if (thisBuf[i] == ch) { + return i; + } + } + return -1; + } + + /** + * Searches the string builder to find the first reference to the specified string. + *

              + * Note that a null input string will return -1, whereas the JDK throws an exception. + * + * @param str the string to find, null returns -1 + * @return the first index of the string, or -1 if not found + */ + public int indexOf(final String str) { + return indexOf(str, 0); + } + + /** + * Searches the string builder to find the first reference to the specified + * string starting searching from the given index. + *

              + * Note that a null input string will return -1, whereas the JDK throws an exception. + * + * @param str the string to find, null returns -1 + * @param startIndex the index to start at, invalid index rounded to edge + * @return the first index of the string, or -1 if not found + */ + public int indexOf(final String str, int startIndex) { + startIndex = (startIndex < 0 ? 0 : startIndex); + if (str == null || startIndex >= size) { + return -1; + } + final int strLen = str.length(); + if (strLen == 1) { + return indexOf(str.charAt(0), startIndex); + } + if (strLen == 0) { + return startIndex; + } + if (strLen > size) { + return -1; + } + final char[] thisBuf = buffer; + final int len = size - strLen + 1; + outer: + for (int i = startIndex; i < len; i++) { + for (int j = 0; j < strLen; j++) { + if (str.charAt(j) != thisBuf[i + j]) { + continue outer; + } + } + return i; + } + return -1; + } + + /** + * Searches the string builder using the matcher to find the first match. + *

              + * Matchers can be used to perform advanced searching behaviour. + * For example you could write a matcher to find the character 'a' + * followed by a number. + * + * @param matcher the matcher to use, null returns -1 + * @return the first index matched, or -1 if not found + */ + public int indexOf(final StrMatcher matcher) { + return indexOf(matcher, 0); + } + + /** + * Searches the string builder using the matcher to find the first + * match searching from the given index. + *

              + * Matchers can be used to perform advanced searching behaviour. + * For example you could write a matcher to find the character 'a' + * followed by a number. + * + * @param matcher the matcher to use, null returns -1 + * @param startIndex the index to start at, invalid index rounded to edge + * @return the first index matched, or -1 if not found + */ + public int indexOf(final StrMatcher matcher, int startIndex) { + startIndex = (startIndex < 0 ? 0 : startIndex); + if (matcher == null || startIndex >= size) { + return -1; + } + final int len = size; + final char[] buf = buffer; + for (int i = startIndex; i < len; i++) { + if (matcher.isMatch(buf, i, startIndex, len) > 0) { + return i; + } + } + return -1; + } + + //----------------------------------------------------------------------- + /** + * Searches the string builder to find the last reference to the specified char. + * + * @param ch the character to find + * @return the last index of the character, or -1 if not found + */ + public int lastIndexOf(final char ch) { + return lastIndexOf(ch, size - 1); + } + + /** + * Searches the string builder to find the last reference to the specified char. + * + * @param ch the character to find + * @param startIndex the index to start at, invalid index rounded to edge + * @return the last index of the character, or -1 if not found + */ + public int lastIndexOf(final char ch, int startIndex) { + startIndex = (startIndex >= size ? size - 1 : startIndex); + if (startIndex < 0) { + return -1; + } + for (int i = startIndex; i >= 0; i--) { + if (buffer[i] == ch) { + return i; + } + } + return -1; + } + + /** + * Searches the string builder to find the last reference to the specified string. + *

              + * Note that a null input string will return -1, whereas the JDK throws an exception. + * + * @param str the string to find, null returns -1 + * @return the last index of the string, or -1 if not found + */ + public int lastIndexOf(final String str) { + return lastIndexOf(str, size - 1); + } + + /** + * Searches the string builder to find the last reference to the specified + * string starting searching from the given index. + *

              + * Note that a null input string will return -1, whereas the JDK throws an exception. + * + * @param str the string to find, null returns -1 + * @param startIndex the index to start at, invalid index rounded to edge + * @return the last index of the string, or -1 if not found + */ + public int lastIndexOf(final String str, int startIndex) { + startIndex = (startIndex >= size ? size - 1 : startIndex); + if (str == null || startIndex < 0) { + return -1; + } + final int strLen = str.length(); + if (strLen > 0 && strLen <= size) { + if (strLen == 1) { + return lastIndexOf(str.charAt(0), startIndex); + } + + outer: + for (int i = startIndex - strLen + 1; i >= 0; i--) { + for (int j = 0; j < strLen; j++) { + if (str.charAt(j) != buffer[i + j]) { + continue outer; + } + } + return i; + } + + } else if (strLen == 0) { + return startIndex; + } + return -1; + } + + /** + * Searches the string builder using the matcher to find the last match. + *

              + * Matchers can be used to perform advanced searching behaviour. + * For example you could write a matcher to find the character 'a' + * followed by a number. + * + * @param matcher the matcher to use, null returns -1 + * @return the last index matched, or -1 if not found + */ + public int lastIndexOf(final StrMatcher matcher) { + return lastIndexOf(matcher, size); + } + + /** + * Searches the string builder using the matcher to find the last + * match searching from the given index. + *

              + * Matchers can be used to perform advanced searching behaviour. + * For example you could write a matcher to find the character 'a' + * followed by a number. + * + * @param matcher the matcher to use, null returns -1 + * @param startIndex the index to start at, invalid index rounded to edge + * @return the last index matched, or -1 if not found + */ + public int lastIndexOf(final StrMatcher matcher, int startIndex) { + startIndex = (startIndex >= size ? size - 1 : startIndex); + if (matcher == null || startIndex < 0) { + return -1; + } + final char[] buf = buffer; + final int endIndex = startIndex + 1; + for (int i = startIndex; i >= 0; i--) { + if (matcher.isMatch(buf, i, 0, endIndex) > 0) { + return i; + } + } + return -1; + } + + //----------------------------------------------------------------------- + /** + * Creates a tokenizer that can tokenize the contents of this builder. + *

              + * This method allows the contents of this builder to be tokenized. + * The tokenizer will be setup by default to tokenize on space, tab, + * newline and formfeed (as per StringTokenizer). These values can be + * changed on the tokenizer class, before retrieving the tokens. + *

              + * The returned tokenizer is linked to this builder. You may intermix + * calls to the builder and tokenizer within certain limits, however + * there is no synchronization. Once the tokenizer has been used once, + * it must be {@link StrTokenizer#reset() reset} to pickup the latest + * changes in the builder. For example: + *

              +     * StrBuilder b = new StrBuilder();
              +     * b.append("a b ");
              +     * StrTokenizer t = b.asTokenizer();
              +     * String[] tokens1 = t.getTokenArray();  // returns a,b
              +     * b.append("c d ");
              +     * String[] tokens2 = t.getTokenArray();  // returns a,b (c and d ignored)
              +     * t.reset();              // reset causes builder changes to be picked up
              +     * String[] tokens3 = t.getTokenArray();  // returns a,b,c,d
              +     * 
              + * In addition to simply intermixing appends and tokenization, you can also + * call the set methods on the tokenizer to alter how it tokenizes. Just + * remember to call reset when you want to pickup builder changes. + *

              + * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])} + * with a non-null value will break the link with the builder. + * + * @return a tokenizer that is linked to this builder + */ + public StrTokenizer asTokenizer() { + return new StrBuilderTokenizer(); + } + + //----------------------------------------------------------------------- + /** + * Gets the contents of this builder as a Reader. + *

              + * This method allows the contents of the builder to be read + * using any standard method that expects a Reader. + *

              + * To use, simply create a StrBuilder, populate it with + * data, call asReader, and then read away. + *

              + * The internal character array is shared between the builder and the reader. + * This allows you to append to the builder after creating the reader, + * and the changes will be picked up. + * Note however, that no synchronization occurs, so you must perform + * all operations with the builder and the reader in one thread. + *

              + * The returned reader supports marking, and ignores the flush method. + * + * @return a reader that reads from this builder + */ + public Reader asReader() { + return new StrBuilderReader(); + } + + //----------------------------------------------------------------------- + /** + * Gets this builder as a Writer that can be written to. + *

              + * This method allows you to populate the contents of the builder + * using any standard method that takes a Writer. + *

              + * To use, simply create a StrBuilder, + * call asWriter, and populate away. The data is available + * at any time using the methods of the StrBuilder. + *

              + * The internal character array is shared between the builder and the writer. + * This allows you to intermix calls that append to the builder and + * write using the writer and the changes will be occur correctly. + * Note however, that no synchronization occurs, so you must perform + * all operations with the builder and the writer in one thread. + *

              + * The returned writer ignores the close and flush methods. + * + * @return a writer that populates this builder + */ + public Writer asWriter() { + return new StrBuilderWriter(); + } + + /** + * Appends current contents of this StrBuilder to the + * provided {@link Appendable}. + *

              + * This method tries to avoid doing any extra copies of contents. + * + * @param appendable the appendable to append data to + * @throws IOException if an I/O error occurs + * + * @since 3.4 + * @see #readFrom(Readable) + */ + public void appendTo(final Appendable appendable) throws IOException { + if (appendable instanceof Writer) { + ((Writer) appendable).write(buffer, 0, size); + } else if (appendable instanceof StringBuilder) { + ((StringBuilder) appendable).append(buffer, 0, size); + } else if (appendable instanceof StringBuffer) { + ((StringBuffer) appendable).append(buffer, 0, size); + } else if (appendable instanceof CharBuffer) { + ((CharBuffer) appendable).put(buffer, 0, size); + } else { + appendable.append(this); + } + } + + //----------------------------------------------------------------------- +// /** +// * Gets a String version of the string builder by calling the internal +// * constructor of String by reflection. +// *

              +// * WARNING: You must not use the StrBuilder after calling this method +// * as the buffer is now shared with the String object. To ensure this, +// * the internal character array is set to null, so you will get +// * NullPointerExceptions on all method calls. +// * +// * @return the builder as a String +// */ +// public String toSharedString() { +// try { +// Constructor con = String.class.getDeclaredConstructor( +// new Class[] {int.class, int.class, char[].class}); +// con.setAccessible(true); +// char[] buffer = buf; +// buf = null; +// size = -1; +// nullText = null; +// return (String) con.newInstance( +// new Object[] {Integer.valueOf(0), Integer.valueOf(size), buffer}); +// +// } catch (Exception ex) { +// ex.printStackTrace(); +// throw new UnsupportedOperationException("StrBuilder.toSharedString is unsupported: " + ex.getMessage()); +// } +// } + + //----------------------------------------------------------------------- + /** + * Checks the contents of this builder against another to see if they + * contain the same character content ignoring case. + * + * @param other the object to check, null returns false + * @return true if the builders contain the same characters in the same order + */ + public boolean equalsIgnoreCase(final StrBuilder other) { + if (this == other) { + return true; + } + if (this.size != other.size) { + return false; + } + final char thisBuf[] = this.buffer; + final char otherBuf[] = other.buffer; + for (int i = size - 1; i >= 0; i--) { + final char c1 = thisBuf[i]; + final char c2 = otherBuf[i]; + if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { + return false; + } + } + return true; + } + + /** + * Checks the contents of this builder against another to see if they + * contain the same character content. + * + * @param other the object to check, null returns false + * @return true if the builders contain the same characters in the same order + */ + public boolean equals(final StrBuilder other) { + if (this == other) { + return true; + } + if (other == null) { + return false; + } + if (this.size != other.size) { + return false; + } + final char thisBuf[] = this.buffer; + final char otherBuf[] = other.buffer; + for (int i = size - 1; i >= 0; i--) { + if (thisBuf[i] != otherBuf[i]) { + return false; + } + } + return true; + } + + /** + * Checks the contents of this builder against another to see if they + * contain the same character content. + * + * @param obj the object to check, null returns false + * @return true if the builders contain the same characters in the same order + */ + @Override + public boolean equals(final Object obj) { + return obj instanceof StrBuilder && equals((StrBuilder) obj); + } + + /** + * Gets a suitable hash code for this builder. + * + * @return a hash code + */ + @Override + public int hashCode() { + final char buf[] = buffer; + int hash = 0; + for (int i = size - 1; i >= 0; i--) { + hash = 31 * hash + buf[i]; + } + return hash; + } + + //----------------------------------------------------------------------- + /** + * Gets a String version of the string builder, creating a new instance + * each time the method is called. + *

              + * Note that unlike StringBuffer, the string version returned is + * independent of the string builder. + * + * @return the builder as a String + */ + @Override + public String toString() { + return new String(buffer, 0, size); + } + + /** + * Gets a StringBuffer version of the string builder, creating a + * new instance each time the method is called. + * + * @return the builder as a StringBuffer + */ + public StringBuffer toStringBuffer() { + return new StringBuffer(size).append(buffer, 0, size); + } + + /** + * Gets a StringBuilder version of the string builder, creating a + * new instance each time the method is called. + * + * @return the builder as a StringBuilder + * @since 3.2 + */ + public StringBuilder toStringBuilder() { + return new StringBuilder(size).append(buffer, 0, size); + } + + /** + * Implement the {@link Builder} interface. + * @return the builder as a String + * @since 3.2 + * @see #toString() + */ + @Override + public String build() { + return toString(); + } + + //----------------------------------------------------------------------- + /** + * Validates parameters defining a range of the builder. + * + * @param startIndex the start index, inclusive, must be valid + * @param endIndex the end index, exclusive, must be valid except + * that if too large it is treated as end of string + * @return the new string + * @throws IndexOutOfBoundsException if the index is invalid + */ + protected int validateRange(final int startIndex, int endIndex) { + if (startIndex < 0) { + throw new StringIndexOutOfBoundsException(startIndex); + } + if (endIndex > size) { + endIndex = size; + } + if (startIndex > endIndex) { + throw new StringIndexOutOfBoundsException("end < start"); + } + return endIndex; + } + + /** + * Validates parameters defining a single index in the builder. + * + * @param index the index, must be valid + * @throws IndexOutOfBoundsException if the index is invalid + */ + protected void validateIndex(final int index) { + if (index < 0 || index > size) { + throw new StringIndexOutOfBoundsException(index); + } + } + + //----------------------------------------------------------------------- + /** + * Inner class to allow StrBuilder to operate as a tokenizer. + */ + class StrBuilderTokenizer extends StrTokenizer { + + /** + * Default constructor. + */ + StrBuilderTokenizer() { + super(); + } + + /** {@inheritDoc} */ + @Override + protected List tokenize(final char[] chars, final int offset, final int count) { + if (chars == null) { + return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size()); + } + return super.tokenize(chars, offset, count); + } + + /** {@inheritDoc} */ + @Override + public String getContent() { + final String str = super.getContent(); + if (str == null) { + return StrBuilder.this.toString(); + } + return str; + } + } + + //----------------------------------------------------------------------- + /** + * Inner class to allow StrBuilder to operate as a reader. + */ + class StrBuilderReader extends Reader { + /** The current stream position. */ + private int pos; + /** The last mark position. */ + private int mark; + + /** + * Default constructor. + */ + StrBuilderReader() { + super(); + } + + /** {@inheritDoc} */ + @Override + public void close() { + // do nothing + } + + /** {@inheritDoc} */ + @Override + public int read() { + if (ready() == false) { + return -1; + } + return StrBuilder.this.charAt(pos++); + } + + /** {@inheritDoc} */ + @Override + public int read(final char b[], final int off, int len) { + if (off < 0 || len < 0 || off > b.length || + (off + len) > b.length || (off + len) < 0) { + throw new IndexOutOfBoundsException(); + } + if (len == 0) { + return 0; + } + if (pos >= StrBuilder.this.size()) { + return -1; + } + if (pos + len > size()) { + len = StrBuilder.this.size() - pos; + } + StrBuilder.this.getChars(pos, pos + len, b, off); + pos += len; + return len; + } + + /** {@inheritDoc} */ + @Override + public long skip(long n) { + if (pos + n > StrBuilder.this.size()) { + n = StrBuilder.this.size() - pos; + } + if (n < 0) { + return 0; + } + pos += n; + return n; + } + + /** {@inheritDoc} */ + @Override + public boolean ready() { + return pos < StrBuilder.this.size(); + } + + /** {@inheritDoc} */ + @Override + public boolean markSupported() { + return true; + } + + /** {@inheritDoc} */ + @Override + public void mark(final int readAheadLimit) { + mark = pos; + } + + /** {@inheritDoc} */ + @Override + public void reset() { + pos = mark; + } + } + + //----------------------------------------------------------------------- + /** + * Inner class to allow StrBuilder to operate as a writer. + */ + class StrBuilderWriter extends Writer { + + /** + * Default constructor. + */ + StrBuilderWriter() { + super(); + } + + /** {@inheritDoc} */ + @Override + public void close() { + // do nothing + } + + /** {@inheritDoc} */ + @Override + public void flush() { + // do nothing + } + + /** {@inheritDoc} */ + @Override + public void write(final int c) { + StrBuilder.this.append((char) c); + } + + /** {@inheritDoc} */ + @Override + public void write(final char[] cbuf) { + StrBuilder.this.append(cbuf); + } + + /** {@inheritDoc} */ + @Override + public void write(final char[] cbuf, final int off, final int len) { + StrBuilder.this.append(cbuf, off, len); + } + + /** {@inheritDoc} */ + @Override + public void write(final String str) { + StrBuilder.this.append(str); + } + + /** {@inheritDoc} */ + @Override + public void write(final String str, final int off, final int len) { + StrBuilder.this.append(str, off, len); + } + } + +} diff --git a/src/org/apache/commons/lang3/text/StrLookup.java b/src/org/apache/commons/lang3/text/StrLookup.java new file mode 100644 index 0000000..a99c1b3 --- /dev/null +++ b/src/org/apache/commons/lang3/text/StrLookup.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.util.Map; + +/** + * Lookup a String key to a String value. + *

              + * This class represents the simplest form of a string to string map. + * It has a benefit over a map in that it can create the result on + * demand based on the key. + *

              + * This class comes complete with various factory methods. + * If these do not suffice, you can subclass and implement your own matcher. + *

              + * For example, it would be possible to implement a lookup that used the + * key as a primary key, and looked up the value on demand from the database + * + * @since 2.2 + * @deprecated as of 3.6, use commons-text + * + * StrLookup instead + */ +@Deprecated +public abstract class StrLookup { + + /** + * Lookup that always returns null. + */ + private static final StrLookup NONE_LOOKUP = new MapStrLookup<>(null); + + /** + * Lookup based on system properties. + */ + private static final StrLookup SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup(); + + //----------------------------------------------------------------------- + /** + * Returns a lookup which always returns null. + * + * @return a lookup that always returns null, not null + */ + public static StrLookup noneLookup() { + return NONE_LOOKUP; + } + + /** + * Returns a new lookup which uses a copy of the current + * {@link System#getProperties() System properties}. + *

              + * If a security manager blocked access to system properties, then null will + * be returned from every lookup. + *

              + * If a null key is used, this lookup will throw a NullPointerException. + * + * @return a lookup using system properties, not null + */ + public static StrLookup systemPropertiesLookup() { + return SYSTEM_PROPERTIES_LOOKUP; + } + + /** + * Returns a lookup which looks up values using a map. + *

              + * If the map is null, then null will be returned from every lookup. + * The map result object is converted to a string using toString(). + * + * @param the type of the values supported by the lookup + * @param map the map of keys to values, may be null + * @return a lookup using the map, not null + */ + public static StrLookup mapLookup(final Map map) { + return new MapStrLookup<>(map); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + */ + protected StrLookup() { + super(); + } + + /** + * Looks up a String key to a String value. + *

              + * The internal implementation may use any mechanism to return the value. + * The simplest implementation is to use a Map. However, virtually any + * implementation is possible. + *

              + * For example, it would be possible to implement a lookup that used the + * key as a primary key, and looked up the value on demand from the database + * Or, a numeric based implementation could be created that treats the key + * as an integer, increments the value and return the result as a string - + * converting 1 to 2, 15 to 16 etc. + *

              + * The {@link #lookup(String)} method always returns a String, regardless of + * the underlying data, by converting it as necessary. For example: + *

              +     * Map<String, Object> map = new HashMap<String, Object>();
              +     * map.put("number", Integer.valueOf(2));
              +     * assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
              +     * 
              + * @param key the key to be looked up, may be null + * @return the matching value, null if no match + */ + public abstract String lookup(String key); + + //----------------------------------------------------------------------- + /** + * Lookup implementation that uses a Map. + */ + static class MapStrLookup extends StrLookup { + + /** Map keys are variable names and value. */ + private final Map map; + + /** + * Creates a new instance backed by a Map. + * + * @param map the map of keys to values, may be null + */ + MapStrLookup(final Map map) { + this.map = map; + } + + /** + * Looks up a String key to a String value using the map. + *

              + * If the map is null, then null is returned. + * The map result object is converted to a string using toString(). + * + * @param key the key to be looked up, may be null + * @return the matching value, null if no match + */ + @Override + public String lookup(final String key) { + if (map == null) { + return null; + } + final Object obj = map.get(key); + if (obj == null) { + return null; + } + return obj.toString(); + } + } + + //----------------------------------------------------------------------- + /** + * Lookup implementation based on system properties. + */ + private static class SystemPropertiesStrLookup extends StrLookup { + /** + * {@inheritDoc} This implementation directly accesses system properties. + */ + @Override + public String lookup(final String key) { + if (key.length() > 0) { + try { + return System.getProperty(key); + } catch (final SecurityException scex) { + // Squelched. All lookup(String) will return null. + } + } + return null; + } + } +} diff --git a/src/org/apache/commons/lang3/text/StrMatcher.java b/src/org/apache/commons/lang3/text/StrMatcher.java new file mode 100644 index 0000000..0cfcd6f --- /dev/null +++ b/src/org/apache/commons/lang3/text/StrMatcher.java @@ -0,0 +1,445 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; + +/** + * A matcher class that can be queried to determine if a character array + * portion matches. + *

              + * This class comes complete with various factory methods. + * If these do not suffice, you can subclass and implement your own matcher. + * + * @since 2.2 + * @deprecated as of 3.6, use commons-text + * + * StrMatcher instead + */ +@Deprecated +public abstract class StrMatcher { + + /** + * Matches the comma character. + */ + private static final StrMatcher COMMA_MATCHER = new CharMatcher(','); + /** + * Matches the tab character. + */ + private static final StrMatcher TAB_MATCHER = new CharMatcher('\t'); + /** + * Matches the space character. + */ + private static final StrMatcher SPACE_MATCHER = new CharMatcher(' '); + /** + * Matches the same characters as StringTokenizer, + * namely space, tab, newline, formfeed. + */ + private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray()); + /** + * Matches the String trim() whitespace characters. + */ + private static final StrMatcher TRIM_MATCHER = new TrimMatcher(); + /** + * Matches the double quote character. + */ + private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\''); + /** + * Matches the double quote character. + */ + private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"'); + /** + * Matches the single or double quote character. + */ + private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray()); + /** + * Matches no characters. + */ + private static final StrMatcher NONE_MATCHER = new NoMatcher(); + + // ----------------------------------------------------------------------- + + /** + * Returns a matcher which matches the comma character. + * + * @return a matcher for a comma + */ + public static StrMatcher commaMatcher() { + return COMMA_MATCHER; + } + + /** + * Returns a matcher which matches the tab character. + * + * @return a matcher for a tab + */ + public static StrMatcher tabMatcher() { + return TAB_MATCHER; + } + + /** + * Returns a matcher which matches the space character. + * + * @return a matcher for a space + */ + public static StrMatcher spaceMatcher() { + return SPACE_MATCHER; + } + + /** + * Matches the same characters as StringTokenizer, + * namely space, tab, newline and formfeed. + * + * @return the split matcher + */ + public static StrMatcher splitMatcher() { + return SPLIT_MATCHER; + } + + /** + * Matches the String trim() whitespace characters. + * + * @return the trim matcher + */ + public static StrMatcher trimMatcher() { + return TRIM_MATCHER; + } + + /** + * Returns a matcher which matches the single quote character. + * + * @return a matcher for a single quote + */ + public static StrMatcher singleQuoteMatcher() { + return SINGLE_QUOTE_MATCHER; + } + + /** + * Returns a matcher which matches the double quote character. + * + * @return a matcher for a double quote + */ + public static StrMatcher doubleQuoteMatcher() { + return DOUBLE_QUOTE_MATCHER; + } + + /** + * Returns a matcher which matches the single or double quote character. + * + * @return a matcher for a single or double quote + */ + public static StrMatcher quoteMatcher() { + return QUOTE_MATCHER; + } + + /** + * Matches no characters. + * + * @return a matcher that matches nothing + */ + public static StrMatcher noneMatcher() { + return NONE_MATCHER; + } + + /** + * Constructor that creates a matcher from a character. + * + * @param ch the character to match, must not be null + * @return a new Matcher for the given char + */ + public static StrMatcher charMatcher(final char ch) { + return new CharMatcher(ch); + } + + /** + * Constructor that creates a matcher from a set of characters. + * + * @param chars the characters to match, null or empty matches nothing + * @return a new matcher for the given char[] + */ + public static StrMatcher charSetMatcher(final char... chars) { + if (chars == null || chars.length == 0) { + return NONE_MATCHER; + } + if (chars.length == 1) { + return new CharMatcher(chars[0]); + } + return new CharSetMatcher(chars); + } + + /** + * Constructor that creates a matcher from a string representing a set of characters. + * + * @param chars the characters to match, null or empty matches nothing + * @return a new Matcher for the given characters + */ + public static StrMatcher charSetMatcher(final String chars) { + if (StringUtils.isEmpty(chars)) { + return NONE_MATCHER; + } + if (chars.length() == 1) { + return new CharMatcher(chars.charAt(0)); + } + return new CharSetMatcher(chars.toCharArray()); + } + + /** + * Constructor that creates a matcher from a string. + * + * @param str the string to match, null or empty matches nothing + * @return a new Matcher for the given String + */ + public static StrMatcher stringMatcher(final String str) { + if (StringUtils.isEmpty(str)) { + return NONE_MATCHER; + } + return new StringMatcher(str); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + */ + protected StrMatcher() { + super(); + } + + /** + * Returns the number of matching characters, zero for no match. + *

              + * This method is called to check for a match. + * The parameter pos represents the current position to be + * checked in the string buffer (a character array which must + * not be changed). + * The API guarantees that pos is a valid index for buffer. + *

              + * The character array may be larger than the active area to be matched. + * Only values in the buffer between the specified indices may be accessed. + *

              + * The matching code may check one character or many. + * It may check characters preceding pos as well as those + * after, so long as no checks exceed the bounds specified. + *

              + * It must return zero for no match, or a positive number if a match was found. + * The number indicates the number of characters that matched. + * + * @param buffer the text content to match against, do not change + * @param pos the starting position for the match, valid for buffer + * @param bufferStart the first active index in the buffer, valid for buffer + * @param bufferEnd the end index (exclusive) of the active buffer, valid for buffer + * @return the number of matching characters, zero for no match + */ + public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd); + + /** + * Returns the number of matching characters, zero for no match. + *

              + * This method is called to check for a match. + * The parameter pos represents the current position to be + * checked in the string buffer (a character array which must + * not be changed). + * The API guarantees that pos is a valid index for buffer. + *

              + * The matching code may check one character or many. + * It may check characters preceding pos as well as those after. + *

              + * It must return zero for no match, or a positive number if a match was found. + * The number indicates the number of characters that matched. + * + * @param buffer the text content to match against, do not change + * @param pos the starting position for the match, valid for buffer + * @return the number of matching characters, zero for no match + * @since 2.4 + */ + public int isMatch(final char[] buffer, final int pos) { + return isMatch(buffer, pos, 0, buffer.length); + } + + //----------------------------------------------------------------------- + /** + * Class used to define a set of characters for matching purposes. + */ + static final class CharSetMatcher extends StrMatcher { + /** The set of characters to match. */ + private final char[] chars; + + /** + * Constructor that creates a matcher from a character array. + * + * @param chars the characters to match, must not be null + */ + CharSetMatcher(final char chars[]) { + super(); + this.chars = chars.clone(); + Arrays.sort(this.chars); + } + + /** + * Returns whether or not the given character matches. + * + * @param buffer the text content to match against, do not change + * @param pos the starting position for the match, valid for buffer + * @param bufferStart the first active index in the buffer, valid for buffer + * @param bufferEnd the end index of the active buffer, valid for buffer + * @return the number of matching characters, zero for no match + */ + @Override + public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { + return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0; + } + } + + //----------------------------------------------------------------------- + /** + * Class used to define a character for matching purposes. + */ + static final class CharMatcher extends StrMatcher { + /** The character to match. */ + private final char ch; + + /** + * Constructor that creates a matcher that matches a single character. + * + * @param ch the character to match + */ + CharMatcher(final char ch) { + super(); + this.ch = ch; + } + + /** + * Returns whether or not the given character matches. + * + * @param buffer the text content to match against, do not change + * @param pos the starting position for the match, valid for buffer + * @param bufferStart the first active index in the buffer, valid for buffer + * @param bufferEnd the end index of the active buffer, valid for buffer + * @return the number of matching characters, zero for no match + */ + @Override + public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { + return ch == buffer[pos] ? 1 : 0; + } + } + + //----------------------------------------------------------------------- + /** + * Class used to define a set of characters for matching purposes. + */ + static final class StringMatcher extends StrMatcher { + /** The string to match, as a character array. */ + private final char[] chars; + + /** + * Constructor that creates a matcher from a String. + * + * @param str the string to match, must not be null + */ + StringMatcher(final String str) { + super(); + chars = str.toCharArray(); + } + + /** + * Returns whether or not the given text matches the stored string. + * + * @param buffer the text content to match against, do not change + * @param pos the starting position for the match, valid for buffer + * @param bufferStart the first active index in the buffer, valid for buffer + * @param bufferEnd the end index of the active buffer, valid for buffer + * @return the number of matching characters, zero for no match + */ + @Override + public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) { + final int len = chars.length; + if (pos + len > bufferEnd) { + return 0; + } + for (int i = 0; i < chars.length; i++, pos++) { + if (chars[i] != buffer[pos]) { + return 0; + } + } + return len; + } + + @Override + public String toString() { + return super.toString() + ' ' + Arrays.toString(chars); + } + + } + + //----------------------------------------------------------------------- + /** + * Class used to match no characters. + */ + static final class NoMatcher extends StrMatcher { + + /** + * Constructs a new instance of NoMatcher. + */ + NoMatcher() { + super(); + } + + /** + * Always returns false. + * + * @param buffer the text content to match against, do not change + * @param pos the starting position for the match, valid for buffer + * @param bufferStart the first active index in the buffer, valid for buffer + * @param bufferEnd the end index of the active buffer, valid for buffer + * @return the number of matching characters, zero for no match + */ + @Override + public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { + return 0; + } + } + + //----------------------------------------------------------------------- + /** + * Class used to match whitespace as per trim(). + */ + static final class TrimMatcher extends StrMatcher { + + /** + * Constructs a new instance of TrimMatcher. + */ + TrimMatcher() { + super(); + } + + /** + * Returns whether or not the given character matches. + * + * @param buffer the text content to match against, do not change + * @param pos the starting position for the match, valid for buffer + * @param bufferStart the first active index in the buffer, valid for buffer + * @param bufferEnd the end index of the active buffer, valid for buffer + * @return the number of matching characters, zero for no match + */ + @Override + public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) { + return buffer[pos] <= 32 ? 1 : 0; + } + } + +} diff --git a/src/org/apache/commons/lang3/text/StrSubstitutor.java b/src/org/apache/commons/lang3/text/StrSubstitutor.java new file mode 100644 index 0000000..68f8811 --- /dev/null +++ b/src/org/apache/commons/lang3/text/StrSubstitutor.java @@ -0,0 +1,1235 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.lang3.StringUtils; + +/** + * Substitutes variables within a string by values. + *

              + * This class takes a piece of text and substitutes all the variables within it. + * The default definition of a variable is ${variableName}. + * The prefix and suffix can be changed via constructors and set methods. + *

              + * Variable values are typically resolved from a map, but could also be resolved + * from system properties, or by supplying a custom variable resolver. + *

              + * The simplest example is to use this class to replace Java System properties. For example: + *

              + * StrSubstitutor.replaceSystemProperties(
              + *      "You are running with java.version = ${java.version} and os.name = ${os.name}.");
              + * 
              + *

              + * Typical usage of this class follows the following pattern: First an instance is created + * and initialized with the map that contains the values for the available variables. + * If a prefix and/or suffix for variables should be used other than the default ones, + * the appropriate settings can be performed. After that the replace() + * method can be called passing in the source text for interpolation. In the returned + * text all variable references (as long as their values are known) will be resolved. + * The following example demonstrates this: + *

              + * Map valuesMap = HashMap();
              + * valuesMap.put("animal", "quick brown fox");
              + * valuesMap.put("target", "lazy dog");
              + * String templateString = "The ${animal} jumps over the ${target}.";
              + * StrSubstitutor sub = new StrSubstitutor(valuesMap);
              + * String resolvedString = sub.replace(templateString);
              + * 
              + * yielding: + *
              + *      The quick brown fox jumps over the lazy dog.
              + * 
              + *

              + * Also, this class allows to set a default value for unresolved variables. + * The default value for a variable can be appended to the variable name after the variable + * default value delimiter. The default value of the variable default value delimiter is ':-', + * as in bash and other *nix shells, as those are arguably where the default ${} delimiter set originated. + * The variable default value delimiter can be manually set by calling {@link #setValueDelimiterMatcher(StrMatcher)}, + * {@link #setValueDelimiter(char)} or {@link #setValueDelimiter(String)}. + * The following shows an example with variable default value settings: + *

              + * Map valuesMap = HashMap();
              + * valuesMap.put("animal", "quick brown fox");
              + * valuesMap.put("target", "lazy dog");
              + * String templateString = "The ${animal} jumps over the ${target}. ${undefined.number:-1234567890}.";
              + * StrSubstitutor sub = new StrSubstitutor(valuesMap);
              + * String resolvedString = sub.replace(templateString);
              + * 
              + * yielding: + *
              + *      The quick brown fox jumps over the lazy dog. 1234567890.
              + * 
              + *

              + * In addition to this usage pattern there are some static convenience methods that + * cover the most common use cases. These methods can be used without the need of + * manually creating an instance. However if multiple replace operations are to be + * performed, creating and reusing an instance of this class will be more efficient. + *

              + * Variable replacement works in a recursive way. Thus, if a variable value contains + * a variable then that variable will also be replaced. Cyclic replacements are + * detected and will cause an exception to be thrown. + *

              + * Sometimes the interpolation's result must contain a variable prefix. As an example + * take the following source text: + *

              + *   The variable ${${name}} must be used.
              + * 
              + * Here only the variable's name referred to in the text should be replaced resulting + * in the text (assuming that the value of the name variable is x): + *
              + *   The variable ${x} must be used.
              + * 
              + * To achieve this effect there are two possibilities: Either set a different prefix + * and suffix for variables which do not conflict with the result text you want to + * produce. The other possibility is to use the escape character, by default '$'. + * If this character is placed before a variable reference, this reference is ignored + * and won't be replaced. For example: + *
              + *   The variable $${${name}} must be used.
              + * 
              + *

              + * In some complex scenarios you might even want to perform substitution in the + * names of variables, for instance + *

              + * ${jre-${java.specification.version}}
              + * 
              + * StrSubstitutor supports this recursive substitution in variable + * names, but it has to be enabled explicitly by setting the + * {@link #setEnableSubstitutionInVariables(boolean) enableSubstitutionInVariables} + * property to true. + *

              This class is not thread safe.

              + * + * @since 2.2 + * @deprecated as of 3.6, use commons-text + * + * StrSubstitutor instead + */ +@Deprecated +public class StrSubstitutor { + + /** + * Constant for the default escape character. + */ + public static final char DEFAULT_ESCAPE = '$'; + /** + * Constant for the default variable prefix. + */ + public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher("${"); + /** + * Constant for the default variable suffix. + */ + public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}"); + /** + * Constant for the default value delimiter of a variable. + * @since 3.2 + */ + public static final StrMatcher DEFAULT_VALUE_DELIMITER = StrMatcher.stringMatcher(":-"); + + /** + * Stores the escape character. + */ + private char escapeChar; + /** + * Stores the variable prefix. + */ + private StrMatcher prefixMatcher; + /** + * Stores the variable suffix. + */ + private StrMatcher suffixMatcher; + /** + * Stores the default variable value delimiter + */ + private StrMatcher valueDelimiterMatcher; + /** + * Variable resolution is delegated to an implementor of VariableResolver. + */ + private StrLookup variableResolver; + /** + * The flag whether substitution in variable names is enabled. + */ + private boolean enableSubstitutionInVariables; + /** + * Whether escapes should be preserved. Default is false; + */ + private boolean preserveEscapes = false; + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables in the given source object with + * their matching values from the map. + * + * @param the type of the values in the map + * @param source the source text containing the variables to substitute, null returns null + * @param valueMap the map with the values, may be null + * @return the result of the replace operation + */ + public static String replace(final Object source, final Map valueMap) { + return new StrSubstitutor(valueMap).replace(source); + } + + /** + * Replaces all the occurrences of variables in the given source object with + * their matching values from the map. This method allows to specify a + * custom variable prefix and suffix + * + * @param the type of the values in the map + * @param source the source text containing the variables to substitute, null returns null + * @param valueMap the map with the values, may be null + * @param prefix the prefix of variables, not null + * @param suffix the suffix of variables, not null + * @return the result of the replace operation + * @throws IllegalArgumentException if the prefix or suffix is null + */ + public static String replace(final Object source, final Map valueMap, final String prefix, final String suffix) { + return new StrSubstitutor(valueMap, prefix, suffix).replace(source); + } + + /** + * Replaces all the occurrences of variables in the given source object with their matching + * values from the properties. + * + * @param source the source text containing the variables to substitute, null returns null + * @param valueProperties the properties with values, may be null + * @return the result of the replace operation + */ + public static String replace(final Object source, final Properties valueProperties) { + if (valueProperties == null) { + return source.toString(); + } + final Map valueMap = new HashMap<>(); + final Enumeration propNames = valueProperties.propertyNames(); + while (propNames.hasMoreElements()) { + final String propName = (String)propNames.nextElement(); + final String propValue = valueProperties.getProperty(propName); + valueMap.put(propName, propValue); + } + return StrSubstitutor.replace(source, valueMap); + } + + /** + * Replaces all the occurrences of variables in the given source object with + * their matching values from the system properties. + * + * @param source the source text containing the variables to substitute, null returns null + * @return the result of the replace operation + */ + public static String replaceSystemProperties(final Object source) { + return new StrSubstitutor(StrLookup.systemPropertiesLookup()).replace(source); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance with defaults for variable prefix and suffix + * and the escaping character. + */ + public StrSubstitutor() { + this(null, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); + } + + /** + * Creates a new instance and initializes it. Uses defaults for variable + * prefix and suffix and the escaping character. + * + * @param the type of the values in the map + * @param valueMap the map with the variables' values, may be null + */ + public StrSubstitutor(final Map valueMap) { + this(StrLookup.mapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); + } + + /** + * Creates a new instance and initializes it. Uses a default escaping character. + * + * @param the type of the values in the map + * @param valueMap the map with the variables' values, may be null + * @param prefix the prefix for variables, not null + * @param suffix the suffix for variables, not null + * @throws IllegalArgumentException if the prefix or suffix is null + */ + public StrSubstitutor(final Map valueMap, final String prefix, final String suffix) { + this(StrLookup.mapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE); + } + + /** + * Creates a new instance and initializes it. + * + * @param the type of the values in the map + * @param valueMap the map with the variables' values, may be null + * @param prefix the prefix for variables, not null + * @param suffix the suffix for variables, not null + * @param escape the escape character + * @throws IllegalArgumentException if the prefix or suffix is null + */ + public StrSubstitutor(final Map valueMap, final String prefix, final String suffix, + final char escape) { + this(StrLookup.mapLookup(valueMap), prefix, suffix, escape); + } + + /** + * Creates a new instance and initializes it. + * + * @param the type of the values in the map + * @param valueMap the map with the variables' values, may be null + * @param prefix the prefix for variables, not null + * @param suffix the suffix for variables, not null + * @param escape the escape character + * @param valueDelimiter the variable default value delimiter, may be null + * @throws IllegalArgumentException if the prefix or suffix is null + * @since 3.2 + */ + public StrSubstitutor(final Map valueMap, final String prefix, final String suffix, + final char escape, final String valueDelimiter) { + this(StrLookup.mapLookup(valueMap), prefix, suffix, escape, valueDelimiter); + } + + /** + * Creates a new instance and initializes it. + * + * @param variableResolver the variable resolver, may be null + */ + public StrSubstitutor(final StrLookup variableResolver) { + this(variableResolver, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); + } + + /** + * Creates a new instance and initializes it. + * + * @param variableResolver the variable resolver, may be null + * @param prefix the prefix for variables, not null + * @param suffix the suffix for variables, not null + * @param escape the escape character + * @throws IllegalArgumentException if the prefix or suffix is null + */ + public StrSubstitutor(final StrLookup variableResolver, final String prefix, final String suffix, + final char escape) { + this.setVariableResolver(variableResolver); + this.setVariablePrefix(prefix); + this.setVariableSuffix(suffix); + this.setEscapeChar(escape); + this.setValueDelimiterMatcher(DEFAULT_VALUE_DELIMITER); + } + + /** + * Creates a new instance and initializes it. + * + * @param variableResolver the variable resolver, may be null + * @param prefix the prefix for variables, not null + * @param suffix the suffix for variables, not null + * @param escape the escape character + * @param valueDelimiter the variable default value delimiter string, may be null + * @throws IllegalArgumentException if the prefix or suffix is null + * @since 3.2 + */ + public StrSubstitutor(final StrLookup variableResolver, final String prefix, final String suffix, + final char escape, final String valueDelimiter) { + this.setVariableResolver(variableResolver); + this.setVariablePrefix(prefix); + this.setVariableSuffix(suffix); + this.setEscapeChar(escape); + this.setValueDelimiter(valueDelimiter); + } + + /** + * Creates a new instance and initializes it. + * + * @param variableResolver the variable resolver, may be null + * @param prefixMatcher the prefix for variables, not null + * @param suffixMatcher the suffix for variables, not null + * @param escape the escape character + * @throws IllegalArgumentException if the prefix or suffix is null + */ + public StrSubstitutor( + final StrLookup variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher, + final char escape) { + this(variableResolver, prefixMatcher, suffixMatcher, escape, DEFAULT_VALUE_DELIMITER); + } + + /** + * Creates a new instance and initializes it. + * + * @param variableResolver the variable resolver, may be null + * @param prefixMatcher the prefix for variables, not null + * @param suffixMatcher the suffix for variables, not null + * @param escape the escape character + * @param valueDelimiterMatcher the variable default value delimiter matcher, may be null + * @throws IllegalArgumentException if the prefix or suffix is null + * @since 3.2 + */ + public StrSubstitutor( + final StrLookup variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher, + final char escape, final StrMatcher valueDelimiterMatcher) { + this.setVariableResolver(variableResolver); + this.setVariablePrefixMatcher(prefixMatcher); + this.setVariableSuffixMatcher(suffixMatcher); + this.setEscapeChar(escape); + this.setValueDelimiterMatcher(valueDelimiterMatcher); + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source string as a template. + * + * @param source the string to replace in, null returns null + * @return the result of the replace operation + */ + public String replace(final String source) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(source); + if (substitute(buf, 0, source.length()) == false) { + return source; + } + return buf.toString(); + } + + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source string as a template. + *

              + * Only the specified portion of the string will be processed. + * The rest of the string is not processed, and is not returned. + * + * @param source the string to replace in, null returns null + * @param offset the start offset within the array, must be valid + * @param length the length within the array to be processed, must be valid + * @return the result of the replace operation + */ + public String replace(final String source, final int offset, final int length) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(length).append(source, offset, length); + if (substitute(buf, 0, length) == false) { + return source.substring(offset, offset + length); + } + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source array as a template. + * The array is not altered by this method. + * + * @param source the character array to replace in, not altered, null returns null + * @return the result of the replace operation + */ + public String replace(final char[] source) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(source.length).append(source); + substitute(buf, 0, source.length); + return buf.toString(); + } + + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source array as a template. + * The array is not altered by this method. + *

              + * Only the specified portion of the array will be processed. + * The rest of the array is not processed, and is not returned. + * + * @param source the character array to replace in, not altered, null returns null + * @param offset the start offset within the array, must be valid + * @param length the length within the array to be processed, must be valid + * @return the result of the replace operation + */ + public String replace(final char[] source, final int offset, final int length) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(length).append(source, offset, length); + substitute(buf, 0, length); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source buffer as a template. + * The buffer is not altered by this method. + * + * @param source the buffer to use as a template, not changed, null returns null + * @return the result of the replace operation + */ + public String replace(final StringBuffer source) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(source.length()).append(source); + substitute(buf, 0, buf.length()); + return buf.toString(); + } + + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source buffer as a template. + * The buffer is not altered by this method. + *

              + * Only the specified portion of the buffer will be processed. + * The rest of the buffer is not processed, and is not returned. + * + * @param source the buffer to use as a template, not changed, null returns null + * @param offset the start offset within the array, must be valid + * @param length the length within the array to be processed, must be valid + * @return the result of the replace operation + */ + public String replace(final StringBuffer source, final int offset, final int length) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(length).append(source, offset, length); + substitute(buf, 0, length); + return buf.toString(); + } + + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source as a template. + * The source is not altered by this method. + * + * @param source the buffer to use as a template, not changed, null returns null + * @return the result of the replace operation + * @since 3.2 + */ + public String replace(final CharSequence source) { + if (source == null) { + return null; + } + return replace(source, 0, source.length()); + } + + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source as a template. + * The source is not altered by this method. + *

              + * Only the specified portion of the buffer will be processed. + * The rest of the buffer is not processed, and is not returned. + * + * @param source the buffer to use as a template, not changed, null returns null + * @param offset the start offset within the array, must be valid + * @param length the length within the array to be processed, must be valid + * @return the result of the replace operation + * @since 3.2 + */ + public String replace(final CharSequence source, final int offset, final int length) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(length).append(source, offset, length); + substitute(buf, 0, length); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source builder as a template. + * The builder is not altered by this method. + * + * @param source the builder to use as a template, not changed, null returns null + * @return the result of the replace operation + */ + public String replace(final StrBuilder source) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(source.length()).append(source); + substitute(buf, 0, buf.length()); + return buf.toString(); + } + + /** + * Replaces all the occurrences of variables with their matching values + * from the resolver using the given source builder as a template. + * The builder is not altered by this method. + *

              + * Only the specified portion of the builder will be processed. + * The rest of the builder is not processed, and is not returned. + * + * @param source the builder to use as a template, not changed, null returns null + * @param offset the start offset within the array, must be valid + * @param length the length within the array to be processed, must be valid + * @return the result of the replace operation + */ + public String replace(final StrBuilder source, final int offset, final int length) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder(length).append(source, offset, length); + substitute(buf, 0, length); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables in the given source object with + * their matching values from the resolver. The input source object is + * converted to a string using toString and is not altered. + * + * @param source the source to replace in, null returns null + * @return the result of the replace operation + */ + public String replace(final Object source) { + if (source == null) { + return null; + } + final StrBuilder buf = new StrBuilder().append(source); + substitute(buf, 0, buf.length()); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables within the given source buffer + * with their matching values from the resolver. + * The buffer is updated with the result. + * + * @param source the buffer to replace in, updated, null returns zero + * @return true if altered + */ + public boolean replaceIn(final StringBuffer source) { + if (source == null) { + return false; + } + return replaceIn(source, 0, source.length()); + } + + /** + * Replaces all the occurrences of variables within the given source buffer + * with their matching values from the resolver. + * The buffer is updated with the result. + *

              + * Only the specified portion of the buffer will be processed. + * The rest of the buffer is not processed, but it is not deleted. + * + * @param source the buffer to replace in, updated, null returns zero + * @param offset the start offset within the array, must be valid + * @param length the length within the buffer to be processed, must be valid + * @return true if altered + */ + public boolean replaceIn(final StringBuffer source, final int offset, final int length) { + if (source == null) { + return false; + } + final StrBuilder buf = new StrBuilder(length).append(source, offset, length); + if (substitute(buf, 0, length) == false) { + return false; + } + source.replace(offset, offset + length, buf.toString()); + return true; + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables within the given source buffer + * with their matching values from the resolver. + * The buffer is updated with the result. + * + * @param source the buffer to replace in, updated, null returns zero + * @return true if altered + * @since 3.2 + */ + public boolean replaceIn(final StringBuilder source) { + if (source == null) { + return false; + } + return replaceIn(source, 0, source.length()); + } + + /** + * Replaces all the occurrences of variables within the given source builder + * with their matching values from the resolver. + * The builder is updated with the result. + *

              + * Only the specified portion of the buffer will be processed. + * The rest of the buffer is not processed, but it is not deleted. + * + * @param source the buffer to replace in, updated, null returns zero + * @param offset the start offset within the array, must be valid + * @param length the length within the buffer to be processed, must be valid + * @return true if altered + * @since 3.2 + */ + public boolean replaceIn(final StringBuilder source, final int offset, final int length) { + if (source == null) { + return false; + } + final StrBuilder buf = new StrBuilder(length).append(source, offset, length); + if (substitute(buf, 0, length) == false) { + return false; + } + source.replace(offset, offset + length, buf.toString()); + return true; + } + + //----------------------------------------------------------------------- + /** + * Replaces all the occurrences of variables within the given source + * builder with their matching values from the resolver. + * + * @param source the builder to replace in, updated, null returns zero + * @return true if altered + */ + public boolean replaceIn(final StrBuilder source) { + if (source == null) { + return false; + } + return substitute(source, 0, source.length()); + } + + /** + * Replaces all the occurrences of variables within the given source + * builder with their matching values from the resolver. + *

              + * Only the specified portion of the builder will be processed. + * The rest of the builder is not processed, but it is not deleted. + * + * @param source the builder to replace in, null returns zero + * @param offset the start offset within the array, must be valid + * @param length the length within the builder to be processed, must be valid + * @return true if altered + */ + public boolean replaceIn(final StrBuilder source, final int offset, final int length) { + if (source == null) { + return false; + } + return substitute(source, offset, length); + } + + //----------------------------------------------------------------------- + /** + * Internal method that substitutes the variables. + *

              + * Most users of this class do not need to call this method. This method will + * be called automatically by another (public) method. + *

              + * Writers of subclasses can override this method if they need access to + * the substitution process at the start or end. + * + * @param buf the string builder to substitute into, not null + * @param offset the start offset within the builder, must be valid + * @param length the length within the builder to be processed, must be valid + * @return true if altered + */ + protected boolean substitute(final StrBuilder buf, final int offset, final int length) { + return substitute(buf, offset, length, null) > 0; + } + + /** + * Recursive handler for multiple levels of interpolation. This is the main + * interpolation method, which resolves the values of all variable references + * contained in the passed in text. + * + * @param buf the string builder to substitute into, not null + * @param offset the start offset within the builder, must be valid + * @param length the length within the builder to be processed, must be valid + * @param priorVariables the stack keeping track of the replaced variables, may be null + * @return the length change that occurs, unless priorVariables is null when the int + * represents a boolean flag as to whether any change occurred. + */ + private int substitute(final StrBuilder buf, final int offset, final int length, List priorVariables) { + final StrMatcher pfxMatcher = getVariablePrefixMatcher(); + final StrMatcher suffMatcher = getVariableSuffixMatcher(); + final char escape = getEscapeChar(); + final StrMatcher valueDelimMatcher = getValueDelimiterMatcher(); + final boolean substitutionInVariablesEnabled = isEnableSubstitutionInVariables(); + + final boolean top = priorVariables == null; + boolean altered = false; + int lengthChange = 0; + char[] chars = buf.buffer; + int bufEnd = offset + length; + int pos = offset; + while (pos < bufEnd) { + final int startMatchLen = pfxMatcher.isMatch(chars, pos, offset, + bufEnd); + if (startMatchLen == 0) { + pos++; + } else { + // found variable start marker + if (pos > offset && chars[pos - 1] == escape) { + // escaped + if (preserveEscapes) { + pos++; + continue; + } + buf.deleteCharAt(pos - 1); + chars = buf.buffer; // in case buffer was altered + lengthChange--; + altered = true; + bufEnd--; + } else { + // find suffix + final int startPos = pos; + pos += startMatchLen; + int endMatchLen = 0; + int nestedVarCount = 0; + while (pos < bufEnd) { + if (substitutionInVariablesEnabled + && (endMatchLen = pfxMatcher.isMatch(chars, + pos, offset, bufEnd)) != 0) { + // found a nested variable start + nestedVarCount++; + pos += endMatchLen; + continue; + } + + endMatchLen = suffMatcher.isMatch(chars, pos, offset, + bufEnd); + if (endMatchLen == 0) { + pos++; + } else { + // found variable end marker + if (nestedVarCount == 0) { + String varNameExpr = new String(chars, startPos + + startMatchLen, pos - startPos + - startMatchLen); + if (substitutionInVariablesEnabled) { + final StrBuilder bufName = new StrBuilder(varNameExpr); + substitute(bufName, 0, bufName.length()); + varNameExpr = bufName.toString(); + } + pos += endMatchLen; + final int endPos = pos; + + String varName = varNameExpr; + String varDefaultValue = null; + + if (valueDelimMatcher != null) { + final char [] varNameExprChars = varNameExpr.toCharArray(); + int valueDelimiterMatchLen = 0; + for (int i = 0; i < varNameExprChars.length; i++) { + // if there's any nested variable when nested variable substitution disabled, then stop resolving name and default value. + if (!substitutionInVariablesEnabled + && pfxMatcher.isMatch(varNameExprChars, i, i, varNameExprChars.length) != 0) { + break; + } + if ((valueDelimiterMatchLen = valueDelimMatcher.isMatch(varNameExprChars, i)) != 0) { + varName = varNameExpr.substring(0, i); + varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen); + break; + } + } + } + + // on the first call initialize priorVariables + if (priorVariables == null) { + priorVariables = new ArrayList<>(); + priorVariables.add(new String(chars, + offset, length)); + } + + // handle cyclic substitution + checkCyclicSubstitution(varName, priorVariables); + priorVariables.add(varName); + + // resolve the variable + String varValue = resolveVariable(varName, buf, + startPos, endPos); + if (varValue == null) { + varValue = varDefaultValue; + } + if (varValue != null) { + // recursive replace + final int varLen = varValue.length(); + buf.replace(startPos, endPos, varValue); + altered = true; + int change = substitute(buf, startPos, + varLen, priorVariables); + change = change + + varLen - (endPos - startPos); + pos += change; + bufEnd += change; + lengthChange += change; + chars = buf.buffer; // in case buffer was + // altered + } + + // remove variable from the cyclic stack + priorVariables + .remove(priorVariables.size() - 1); + break; + } + nestedVarCount--; + pos += endMatchLen; + } + } + } + } + } + if (top) { + return altered ? 1 : 0; + } + return lengthChange; + } + + /** + * Checks if the specified variable is already in the stack (list) of variables. + * + * @param varName the variable name to check + * @param priorVariables the list of prior variables + */ + private void checkCyclicSubstitution(final String varName, final List priorVariables) { + if (priorVariables.contains(varName) == false) { + return; + } + final StrBuilder buf = new StrBuilder(256); + buf.append("Infinite loop in property interpolation of "); + buf.append(priorVariables.remove(0)); + buf.append(": "); + buf.appendWithSeparators(priorVariables, "->"); + throw new IllegalStateException(buf.toString()); + } + + /** + * Internal method that resolves the value of a variable. + *

              + * Most users of this class do not need to call this method. This method is + * called automatically by the substitution process. + *

              + * Writers of subclasses can override this method if they need to alter + * how each substitution occurs. The method is passed the variable's name + * and must return the corresponding value. This implementation uses the + * {@link #getVariableResolver()} with the variable's name as the key. + * + * @param variableName the name of the variable, not null + * @param buf the buffer where the substitution is occurring, not null + * @param startPos the start position of the variable including the prefix, valid + * @param endPos the end position of the variable including the suffix, valid + * @return the variable's value or null if the variable is unknown + */ + protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) { + final StrLookup resolver = getVariableResolver(); + if (resolver == null) { + return null; + } + return resolver.lookup(variableName); + } + + // Escape + //----------------------------------------------------------------------- + /** + * Returns the escape character. + * + * @return the character used for escaping variable references + */ + public char getEscapeChar() { + return this.escapeChar; + } + + /** + * Sets the escape character. + * If this character is placed before a variable reference in the source + * text, this variable will be ignored. + * + * @param escapeCharacter the escape character (0 for disabling escaping) + */ + public void setEscapeChar(final char escapeCharacter) { + this.escapeChar = escapeCharacter; + } + + // Prefix + //----------------------------------------------------------------------- + /** + * Gets the variable prefix matcher currently in use. + *

              + * The variable prefix is the character or characters that identify the + * start of a variable. This prefix is expressed in terms of a matcher + * allowing advanced prefix matches. + * + * @return the prefix matcher in use + */ + public StrMatcher getVariablePrefixMatcher() { + return prefixMatcher; + } + + /** + * Sets the variable prefix matcher currently in use. + *

              + * The variable prefix is the character or characters that identify the + * start of a variable. This prefix is expressed in terms of a matcher + * allowing advanced prefix matches. + * + * @param prefixMatcher the prefix matcher to use, null ignored + * @return this, to enable chaining + * @throws IllegalArgumentException if the prefix matcher is null + */ + public StrSubstitutor setVariablePrefixMatcher(final StrMatcher prefixMatcher) { + if (prefixMatcher == null) { + throw new IllegalArgumentException("Variable prefix matcher must not be null!"); + } + this.prefixMatcher = prefixMatcher; + return this; + } + + /** + * Sets the variable prefix to use. + *

              + * The variable prefix is the character or characters that identify the + * start of a variable. This method allows a single character prefix to + * be easily set. + * + * @param prefix the prefix character to use + * @return this, to enable chaining + */ + public StrSubstitutor setVariablePrefix(final char prefix) { + return setVariablePrefixMatcher(StrMatcher.charMatcher(prefix)); + } + + /** + * Sets the variable prefix to use. + *

              + * The variable prefix is the character or characters that identify the + * start of a variable. This method allows a string prefix to be easily set. + * + * @param prefix the prefix for variables, not null + * @return this, to enable chaining + * @throws IllegalArgumentException if the prefix is null + */ + public StrSubstitutor setVariablePrefix(final String prefix) { + if (prefix == null) { + throw new IllegalArgumentException("Variable prefix must not be null!"); + } + return setVariablePrefixMatcher(StrMatcher.stringMatcher(prefix)); + } + + // Suffix + //----------------------------------------------------------------------- + /** + * Gets the variable suffix matcher currently in use. + *

              + * The variable suffix is the character or characters that identify the + * end of a variable. This suffix is expressed in terms of a matcher + * allowing advanced suffix matches. + * + * @return the suffix matcher in use + */ + public StrMatcher getVariableSuffixMatcher() { + return suffixMatcher; + } + + /** + * Sets the variable suffix matcher currently in use. + *

              + * The variable suffix is the character or characters that identify the + * end of a variable. This suffix is expressed in terms of a matcher + * allowing advanced suffix matches. + * + * @param suffixMatcher the suffix matcher to use, null ignored + * @return this, to enable chaining + * @throws IllegalArgumentException if the suffix matcher is null + */ + public StrSubstitutor setVariableSuffixMatcher(final StrMatcher suffixMatcher) { + if (suffixMatcher == null) { + throw new IllegalArgumentException("Variable suffix matcher must not be null!"); + } + this.suffixMatcher = suffixMatcher; + return this; + } + + /** + * Sets the variable suffix to use. + *

              + * The variable suffix is the character or characters that identify the + * end of a variable. This method allows a single character suffix to + * be easily set. + * + * @param suffix the suffix character to use + * @return this, to enable chaining + */ + public StrSubstitutor setVariableSuffix(final char suffix) { + return setVariableSuffixMatcher(StrMatcher.charMatcher(suffix)); + } + + /** + * Sets the variable suffix to use. + *

              + * The variable suffix is the character or characters that identify the + * end of a variable. This method allows a string suffix to be easily set. + * + * @param suffix the suffix for variables, not null + * @return this, to enable chaining + * @throws IllegalArgumentException if the suffix is null + */ + public StrSubstitutor setVariableSuffix(final String suffix) { + if (suffix == null) { + throw new IllegalArgumentException("Variable suffix must not be null!"); + } + return setVariableSuffixMatcher(StrMatcher.stringMatcher(suffix)); + } + + // Variable Default Value Delimiter + //----------------------------------------------------------------------- + /** + * Gets the variable default value delimiter matcher currently in use. + *

              + * The variable default value delimiter is the character or characters that delimit the + * variable name and the variable default value. This delimiter is expressed in terms of a matcher + * allowing advanced variable default value delimiter matches. + *

              + * If it returns null, then the variable default value resolution is disabled. + * + * @return the variable default value delimiter matcher in use, may be null + * @since 3.2 + */ + public StrMatcher getValueDelimiterMatcher() { + return valueDelimiterMatcher; + } + + /** + * Sets the variable default value delimiter matcher to use. + *

              + * The variable default value delimiter is the character or characters that delimit the + * variable name and the variable default value. This delimiter is expressed in terms of a matcher + * allowing advanced variable default value delimiter matches. + *

              + * If the valueDelimiterMatcher is null, then the variable default value resolution + * becomes disabled. + * + * @param valueDelimiterMatcher variable default value delimiter matcher to use, may be null + * @return this, to enable chaining + * @since 3.2 + */ + public StrSubstitutor setValueDelimiterMatcher(final StrMatcher valueDelimiterMatcher) { + this.valueDelimiterMatcher = valueDelimiterMatcher; + return this; + } + + /** + * Sets the variable default value delimiter to use. + *

              + * The variable default value delimiter is the character or characters that delimit the + * variable name and the variable default value. This method allows a single character + * variable default value delimiter to be easily set. + * + * @param valueDelimiter the variable default value delimiter character to use + * @return this, to enable chaining + * @since 3.2 + */ + public StrSubstitutor setValueDelimiter(final char valueDelimiter) { + return setValueDelimiterMatcher(StrMatcher.charMatcher(valueDelimiter)); + } + + /** + * Sets the variable default value delimiter to use. + *

              + * The variable default value delimiter is the character or characters that delimit the + * variable name and the variable default value. This method allows a string + * variable default value delimiter to be easily set. + *

              + * If the valueDelimiter is null or empty string, then the variable default + * value resolution becomes disabled. + * + * @param valueDelimiter the variable default value delimiter string to use, may be null or empty + * @return this, to enable chaining + * @since 3.2 + */ + public StrSubstitutor setValueDelimiter(final String valueDelimiter) { + if (StringUtils.isEmpty(valueDelimiter)) { + setValueDelimiterMatcher(null); + return this; + } + return setValueDelimiterMatcher(StrMatcher.stringMatcher(valueDelimiter)); + } + + // Resolver + //----------------------------------------------------------------------- + /** + * Gets the VariableResolver that is used to lookup variables. + * + * @return the VariableResolver + */ + public StrLookup getVariableResolver() { + return this.variableResolver; + } + + /** + * Sets the VariableResolver that is used to lookup variables. + * + * @param variableResolver the VariableResolver + */ + public void setVariableResolver(final StrLookup variableResolver) { + this.variableResolver = variableResolver; + } + + // Substitution support in variable names + //----------------------------------------------------------------------- + /** + * Returns a flag whether substitution is done in variable names. + * + * @return the substitution in variable names flag + * @since 3.0 + */ + public boolean isEnableSubstitutionInVariables() { + return enableSubstitutionInVariables; + } + + /** + * Sets a flag whether substitution is done in variable names. If set to + * true, the names of variables can contain other variables which are + * processed first before the original variable is evaluated, e.g. + * ${jre-${java.version}}. The default value is false. + * + * @param enableSubstitutionInVariables the new value of the flag + * @since 3.0 + */ + public void setEnableSubstitutionInVariables( + final boolean enableSubstitutionInVariables) { + this.enableSubstitutionInVariables = enableSubstitutionInVariables; + } + + /** + * Returns the flag controlling whether escapes are preserved during + * substitution. + * + * @return the preserve escape flag + * @since 3.5 + */ + public boolean isPreserveEscapes() { + return preserveEscapes; + } + + /** + * Sets a flag controlling whether escapes are preserved during + * substitution. If set to true, the escape character is retained + * during substitution (e.g. $${this-is-escaped} remains + * $${this-is-escaped}). If set to false, the escape + * character is removed during substitution (e.g. + * $${this-is-escaped} becomes + * ${this-is-escaped}). The default value is false + * + * @param preserveEscapes true if escapes are to be preserved + * @since 3.5 + */ + public void setPreserveEscapes(final boolean preserveEscapes) { + this.preserveEscapes = preserveEscapes; + } +} diff --git a/src/org/apache/commons/lang3/text/StrTokenizer.java b/src/org/apache/commons/lang3/text/StrTokenizer.java new file mode 100644 index 0000000..8d56b1d --- /dev/null +++ b/src/org/apache/commons/lang3/text/StrTokenizer.java @@ -0,0 +1,1117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +/** + * Tokenizes a string based based on delimiters (separators) + * and supporting quoting and ignored character concepts. + *

              + * This class can split a String into many smaller strings. It aims + * to do a similar job to {@link java.util.StringTokenizer StringTokenizer}, + * however it offers much more control and flexibility including implementing + * the ListIterator interface. By default, it is set up + * like StringTokenizer. + *

              + * The input String is split into a number of tokens. + * Each token is separated from the next String by a delimiter. + * One or more delimiter characters must be specified. + *

              + * Each token may be surrounded by quotes. + * The quote matcher specifies the quote character(s). + * A quote may be escaped within a quoted section by duplicating itself. + *

              + * Between each token and the delimiter are potentially characters that need trimming. + * The trimmer matcher specifies these characters. + * One usage might be to trim whitespace characters. + *

              + * At any point outside the quotes there might potentially be invalid characters. + * The ignored matcher specifies these characters to be removed. + * One usage might be to remove new line characters. + *

              + * Empty tokens may be removed or returned as null. + *

              + * "a,b,c"         - Three tokens "a","b","c"   (comma delimiter)
              + * " a, b , c "    - Three tokens "a","b","c"   (default CSV processing trims whitespace)
              + * "a, ", b ,", c" - Three tokens "a, " , " b ", ", c" (quoted text untouched)
              + * 
              + *

              + * + * This tokenizer has the following properties and options: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
              PropertyTypeDefault
              delimCharSetMatcher{ \t\n\r\f}
              quoteNoneMatcher{}
              ignoreNoneMatcher{}
              emptyTokenAsNullbooleanfalse
              ignoreEmptyTokensbooleantrue
              + * + * @since 2.2 + * @deprecated as of 3.6, use commons-text + * + * StrTokenizer instead + */ +@Deprecated +public class StrTokenizer implements ListIterator, Cloneable { + + private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE; + private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE; + static { + CSV_TOKENIZER_PROTOTYPE = new StrTokenizer(); + CSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.commaMatcher()); + CSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher()); + CSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher()); + CSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher()); + CSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false); + CSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false); + + TSV_TOKENIZER_PROTOTYPE = new StrTokenizer(); + TSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.tabMatcher()); + TSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher()); + TSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher()); + TSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher()); + TSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false); + TSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false); + } + + /** The text to work on. */ + private char chars[]; + /** The parsed tokens */ + private String tokens[]; + /** The current iteration position */ + private int tokenPos; + + /** The delimiter matcher */ + private StrMatcher delimMatcher = StrMatcher.splitMatcher(); + /** The quote matcher */ + private StrMatcher quoteMatcher = StrMatcher.noneMatcher(); + /** The ignored matcher */ + private StrMatcher ignoredMatcher = StrMatcher.noneMatcher(); + /** The trimmer matcher */ + private StrMatcher trimmerMatcher = StrMatcher.noneMatcher(); + + /** Whether to return empty tokens as null */ + private boolean emptyAsNull = false; + /** Whether to ignore empty tokens */ + private boolean ignoreEmptyTokens = true; + + //----------------------------------------------------------------------- + + /** + * Returns a clone of CSV_TOKENIZER_PROTOTYPE. + * + * @return a clone of CSV_TOKENIZER_PROTOTYPE. + */ + private static StrTokenizer getCSVClone() { + return (StrTokenizer) CSV_TOKENIZER_PROTOTYPE.clone(); + } + + /** + * Gets a new tokenizer instance which parses Comma Separated Value strings + * initializing it with the given input. The default for CSV processing + * will be trim whitespace from both ends (which can be overridden with + * the setTrimmer method). + *

              + * You must call a "reset" method to set the string which you want to parse. + * @return a new tokenizer instance which parses Comma Separated Value strings + */ + public static StrTokenizer getCSVInstance() { + return getCSVClone(); + } + + /** + * Gets a new tokenizer instance which parses Comma Separated Value strings + * initializing it with the given input. The default for CSV processing + * will be trim whitespace from both ends (which can be overridden with + * the setTrimmer method). + * + * @param input the text to parse + * @return a new tokenizer instance which parses Comma Separated Value strings + */ + public static StrTokenizer getCSVInstance(final String input) { + final StrTokenizer tok = getCSVClone(); + tok.reset(input); + return tok; + } + + /** + * Gets a new tokenizer instance which parses Comma Separated Value strings + * initializing it with the given input. The default for CSV processing + * will be trim whitespace from both ends (which can be overridden with + * the setTrimmer method). + * + * @param input the text to parse + * @return a new tokenizer instance which parses Comma Separated Value strings + */ + public static StrTokenizer getCSVInstance(final char[] input) { + final StrTokenizer tok = getCSVClone(); + tok.reset(input); + return tok; + } + + /** + * Returns a clone of TSV_TOKENIZER_PROTOTYPE. + * + * @return a clone of TSV_TOKENIZER_PROTOTYPE. + */ + private static StrTokenizer getTSVClone() { + return (StrTokenizer) TSV_TOKENIZER_PROTOTYPE.clone(); + } + + + /** + * Gets a new tokenizer instance which parses Tab Separated Value strings. + * The default for CSV processing will be trim whitespace from both ends + * (which can be overridden with the setTrimmer method). + *

              + * You must call a "reset" method to set the string which you want to parse. + * @return a new tokenizer instance which parses Tab Separated Value strings. + */ + public static StrTokenizer getTSVInstance() { + return getTSVClone(); + } + + /** + * Gets a new tokenizer instance which parses Tab Separated Value strings. + * The default for CSV processing will be trim whitespace from both ends + * (which can be overridden with the setTrimmer method). + * @param input the string to parse + * @return a new tokenizer instance which parses Tab Separated Value strings. + */ + public static StrTokenizer getTSVInstance(final String input) { + final StrTokenizer tok = getTSVClone(); + tok.reset(input); + return tok; + } + + /** + * Gets a new tokenizer instance which parses Tab Separated Value strings. + * The default for CSV processing will be trim whitespace from both ends + * (which can be overridden with the setTrimmer method). + * @param input the string to parse + * @return a new tokenizer instance which parses Tab Separated Value strings. + */ + public static StrTokenizer getTSVInstance(final char[] input) { + final StrTokenizer tok = getTSVClone(); + tok.reset(input); + return tok; + } + + //----------------------------------------------------------------------- + /** + * Constructs a tokenizer splitting on space, tab, newline and formfeed + * as per StringTokenizer, but with no text to tokenize. + *

              + * This constructor is normally used with {@link #reset(String)}. + */ + public StrTokenizer() { + super(); + this.chars = null; + } + + /** + * Constructs a tokenizer splitting on space, tab, newline and formfeed + * as per StringTokenizer. + * + * @param input the string which is to be parsed + */ + public StrTokenizer(final String input) { + super(); + if (input != null) { + chars = input.toCharArray(); + } else { + chars = null; + } + } + + /** + * Constructs a tokenizer splitting on the specified delimiter character. + * + * @param input the string which is to be parsed + * @param delim the field delimiter character + */ + public StrTokenizer(final String input, final char delim) { + this(input); + setDelimiterChar(delim); + } + + /** + * Constructs a tokenizer splitting on the specified delimiter string. + * + * @param input the string which is to be parsed + * @param delim the field delimiter string + */ + public StrTokenizer(final String input, final String delim) { + this(input); + setDelimiterString(delim); + } + + /** + * Constructs a tokenizer splitting using the specified delimiter matcher. + * + * @param input the string which is to be parsed + * @param delim the field delimiter matcher + */ + public StrTokenizer(final String input, final StrMatcher delim) { + this(input); + setDelimiterMatcher(delim); + } + + /** + * Constructs a tokenizer splitting on the specified delimiter character + * and handling quotes using the specified quote character. + * + * @param input the string which is to be parsed + * @param delim the field delimiter character + * @param quote the field quoted string character + */ + public StrTokenizer(final String input, final char delim, final char quote) { + this(input, delim); + setQuoteChar(quote); + } + + /** + * Constructs a tokenizer splitting using the specified delimiter matcher + * and handling quotes using the specified quote matcher. + * + * @param input the string which is to be parsed + * @param delim the field delimiter matcher + * @param quote the field quoted string matcher + */ + public StrTokenizer(final String input, final StrMatcher delim, final StrMatcher quote) { + this(input, delim); + setQuoteMatcher(quote); + } + + /** + * Constructs a tokenizer splitting on space, tab, newline and formfeed + * as per StringTokenizer. + * + * @param input the string which is to be parsed, not cloned + */ + public StrTokenizer(final char[] input) { + super(); + this.chars = ArrayUtils.clone(input); + } + + /** + * Constructs a tokenizer splitting on the specified character. + * + * @param input the string which is to be parsed, not cloned + * @param delim the field delimiter character + */ + public StrTokenizer(final char[] input, final char delim) { + this(input); + setDelimiterChar(delim); + } + + /** + * Constructs a tokenizer splitting on the specified string. + * + * @param input the string which is to be parsed, not cloned + * @param delim the field delimiter string + */ + public StrTokenizer(final char[] input, final String delim) { + this(input); + setDelimiterString(delim); + } + + /** + * Constructs a tokenizer splitting using the specified delimiter matcher. + * + * @param input the string which is to be parsed, not cloned + * @param delim the field delimiter matcher + */ + public StrTokenizer(final char[] input, final StrMatcher delim) { + this(input); + setDelimiterMatcher(delim); + } + + /** + * Constructs a tokenizer splitting on the specified delimiter character + * and handling quotes using the specified quote character. + * + * @param input the string which is to be parsed, not cloned + * @param delim the field delimiter character + * @param quote the field quoted string character + */ + public StrTokenizer(final char[] input, final char delim, final char quote) { + this(input, delim); + setQuoteChar(quote); + } + + /** + * Constructs a tokenizer splitting using the specified delimiter matcher + * and handling quotes using the specified quote matcher. + * + * @param input the string which is to be parsed, not cloned + * @param delim the field delimiter character + * @param quote the field quoted string character + */ + public StrTokenizer(final char[] input, final StrMatcher delim, final StrMatcher quote) { + this(input, delim); + setQuoteMatcher(quote); + } + + // API + //----------------------------------------------------------------------- + /** + * Gets the number of tokens found in the String. + * + * @return the number of matched tokens + */ + public int size() { + checkTokenized(); + return tokens.length; + } + + /** + * Gets the next token from the String. + * Equivalent to {@link #next()} except it returns null rather than + * throwing {@link NoSuchElementException} when no tokens remain. + * + * @return the next sequential token, or null when no more tokens are found + */ + public String nextToken() { + if (hasNext()) { + return tokens[tokenPos++]; + } + return null; + } + + /** + * Gets the previous token from the String. + * + * @return the previous sequential token, or null when no more tokens are found + */ + public String previousToken() { + if (hasPrevious()) { + return tokens[--tokenPos]; + } + return null; + } + + /** + * Gets a copy of the full token list as an independent modifiable array. + * + * @return the tokens as a String array + */ + public String[] getTokenArray() { + checkTokenized(); + return tokens.clone(); + } + + /** + * Gets a copy of the full token list as an independent modifiable list. + * + * @return the tokens as a String array + */ + public List getTokenList() { + checkTokenized(); + final List list = new ArrayList<>(tokens.length); + for (final String element : tokens) { + list.add(element); + } + return list; + } + + /** + * Resets this tokenizer, forgetting all parsing and iteration already completed. + *

              + * This method allows the same tokenizer to be reused for the same String. + * + * @return this, to enable chaining + */ + public StrTokenizer reset() { + tokenPos = 0; + tokens = null; + return this; + } + + /** + * Reset this tokenizer, giving it a new input string to parse. + * In this manner you can re-use a tokenizer with the same settings + * on multiple input lines. + * + * @param input the new string to tokenize, null sets no text to parse + * @return this, to enable chaining + */ + public StrTokenizer reset(final String input) { + reset(); + if (input != null) { + this.chars = input.toCharArray(); + } else { + this.chars = null; + } + return this; + } + + /** + * Reset this tokenizer, giving it a new input string to parse. + * In this manner you can re-use a tokenizer with the same settings + * on multiple input lines. + * + * @param input the new character array to tokenize, not cloned, null sets no text to parse + * @return this, to enable chaining + */ + public StrTokenizer reset(final char[] input) { + reset(); + this.chars = ArrayUtils.clone(input); + return this; + } + + // ListIterator + //----------------------------------------------------------------------- + /** + * Checks whether there are any more tokens. + * + * @return true if there are more tokens + */ + @Override + public boolean hasNext() { + checkTokenized(); + return tokenPos < tokens.length; + } + + /** + * Gets the next token. + * + * @return the next String token + * @throws NoSuchElementException if there are no more elements + */ + @Override + public String next() { + if (hasNext()) { + return tokens[tokenPos++]; + } + throw new NoSuchElementException(); + } + + /** + * Gets the index of the next token to return. + * + * @return the next token index + */ + @Override + public int nextIndex() { + return tokenPos; + } + + /** + * Checks whether there are any previous tokens that can be iterated to. + * + * @return true if there are previous tokens + */ + @Override + public boolean hasPrevious() { + checkTokenized(); + return tokenPos > 0; + } + + /** + * Gets the token previous to the last returned token. + * + * @return the previous token + */ + @Override + public String previous() { + if (hasPrevious()) { + return tokens[--tokenPos]; + } + throw new NoSuchElementException(); + } + + /** + * Gets the index of the previous token. + * + * @return the previous token index + */ + @Override + public int previousIndex() { + return tokenPos - 1; + } + + /** + * Unsupported ListIterator operation. + * + * @throws UnsupportedOperationException always + */ + @Override + public void remove() { + throw new UnsupportedOperationException("remove() is unsupported"); + } + + /** + * Unsupported ListIterator operation. + * @param obj this parameter ignored. + * @throws UnsupportedOperationException always + */ + @Override + public void set(final String obj) { + throw new UnsupportedOperationException("set() is unsupported"); + } + + /** + * Unsupported ListIterator operation. + * @param obj this parameter ignored. + * @throws UnsupportedOperationException always + */ + @Override + public void add(final String obj) { + throw new UnsupportedOperationException("add() is unsupported"); + } + + // Implementation + //----------------------------------------------------------------------- + /** + * Checks if tokenization has been done, and if not then do it. + */ + private void checkTokenized() { + if (tokens == null) { + if (chars == null) { + // still call tokenize as subclass may do some work + final List split = tokenize(null, 0, 0); + tokens = split.toArray(new String[split.size()]); + } else { + final List split = tokenize(chars, 0, chars.length); + tokens = split.toArray(new String[split.size()]); + } + } + } + + /** + * Internal method to performs the tokenization. + *

              + * Most users of this class do not need to call this method. This method + * will be called automatically by other (public) methods when required. + *

              + * This method exists to allow subclasses to add code before or after the + * tokenization. For example, a subclass could alter the character array, + * offset or count to be parsed, or call the tokenizer multiple times on + * multiple strings. It is also be possible to filter the results. + *

              + * StrTokenizer will always pass a zero offset and a count + * equal to the length of the array to this method, however a subclass + * may pass other values, or even an entirely different array. + * + * @param srcChars the character array being tokenized, may be null + * @param offset the start position within the character array, must be valid + * @param count the number of characters to tokenize, must be valid + * @return the modifiable list of String tokens, unmodifiable if null array or zero count + */ + protected List tokenize(final char[] srcChars, final int offset, final int count) { + if (srcChars == null || count == 0) { + return Collections.emptyList(); + } + final StrBuilder buf = new StrBuilder(); + final List tokenList = new ArrayList<>(); + int pos = offset; + + // loop around the entire buffer + while (pos >= 0 && pos < count) { + // find next token + pos = readNextToken(srcChars, pos, count, buf, tokenList); + + // handle case where end of string is a delimiter + if (pos >= count) { + addToken(tokenList, StringUtils.EMPTY); + } + } + return tokenList; + } + + /** + * Adds a token to a list, paying attention to the parameters we've set. + * + * @param list the list to add to + * @param tok the token to add + */ + private void addToken(final List list, String tok) { + if (StringUtils.isEmpty(tok)) { + if (isIgnoreEmptyTokens()) { + return; + } + if (isEmptyTokenAsNull()) { + tok = null; + } + } + list.add(tok); + } + + /** + * Reads character by character through the String to get the next token. + * + * @param srcChars the character array being tokenized + * @param start the first character of field + * @param len the length of the character array being tokenized + * @param workArea a temporary work area + * @param tokenList the list of parsed tokens + * @return the starting position of the next field (the character + * immediately after the delimiter), or -1 if end of string found + */ + private int readNextToken(final char[] srcChars, int start, final int len, final StrBuilder workArea, final List tokenList) { + // skip all leading whitespace, unless it is the + // field delimiter or the quote character + while (start < len) { + final int removeLen = Math.max( + getIgnoredMatcher().isMatch(srcChars, start, start, len), + getTrimmerMatcher().isMatch(srcChars, start, start, len)); + if (removeLen == 0 || + getDelimiterMatcher().isMatch(srcChars, start, start, len) > 0 || + getQuoteMatcher().isMatch(srcChars, start, start, len) > 0) { + break; + } + start += removeLen; + } + + // handle reaching end + if (start >= len) { + addToken(tokenList, StringUtils.EMPTY); + return -1; + } + + // handle empty token + final int delimLen = getDelimiterMatcher().isMatch(srcChars, start, start, len); + if (delimLen > 0) { + addToken(tokenList, StringUtils.EMPTY); + return start + delimLen; + } + + // handle found token + final int quoteLen = getQuoteMatcher().isMatch(srcChars, start, start, len); + if (quoteLen > 0) { + return readWithQuotes(srcChars, start + quoteLen, len, workArea, tokenList, start, quoteLen); + } + return readWithQuotes(srcChars, start, len, workArea, tokenList, 0, 0); + } + + /** + * Reads a possibly quoted string token. + * + * @param srcChars the character array being tokenized + * @param start the first character of field + * @param len the length of the character array being tokenized + * @param workArea a temporary work area + * @param tokenList the list of parsed tokens + * @param quoteStart the start position of the matched quote, 0 if no quoting + * @param quoteLen the length of the matched quote, 0 if no quoting + * @return the starting position of the next field (the character + * immediately after the delimiter, or if end of string found, + * then the length of string + */ + private int readWithQuotes(final char[] srcChars, final int start, final int len, final StrBuilder workArea, + final List tokenList, final int quoteStart, final int quoteLen) { + // Loop until we've found the end of the quoted + // string or the end of the input + workArea.clear(); + int pos = start; + boolean quoting = quoteLen > 0; + int trimStart = 0; + + while (pos < len) { + // quoting mode can occur several times throughout a string + // we must switch between quoting and non-quoting until we + // encounter a non-quoted delimiter, or end of string + if (quoting) { + // In quoting mode + + // If we've found a quote character, see if it's + // followed by a second quote. If so, then we need + // to actually put the quote character into the token + // rather than end the token. + if (isQuote(srcChars, pos, len, quoteStart, quoteLen)) { + if (isQuote(srcChars, pos + quoteLen, len, quoteStart, quoteLen)) { + // matched pair of quotes, thus an escaped quote + workArea.append(srcChars, pos, quoteLen); + pos += quoteLen * 2; + trimStart = workArea.size(); + continue; + } + + // end of quoting + quoting = false; + pos += quoteLen; + continue; + } + + // copy regular character from inside quotes + workArea.append(srcChars[pos++]); + trimStart = workArea.size(); + + } else { + // Not in quoting mode + + // check for delimiter, and thus end of token + final int delimLen = getDelimiterMatcher().isMatch(srcChars, pos, start, len); + if (delimLen > 0) { + // return condition when end of token found + addToken(tokenList, workArea.substring(0, trimStart)); + return pos + delimLen; + } + + // check for quote, and thus back into quoting mode + if (quoteLen > 0 && isQuote(srcChars, pos, len, quoteStart, quoteLen)) { + quoting = true; + pos += quoteLen; + continue; + } + + // check for ignored (outside quotes), and ignore + final int ignoredLen = getIgnoredMatcher().isMatch(srcChars, pos, start, len); + if (ignoredLen > 0) { + pos += ignoredLen; + continue; + } + + // check for trimmed character + // don't yet know if its at the end, so copy to workArea + // use trimStart to keep track of trim at the end + final int trimmedLen = getTrimmerMatcher().isMatch(srcChars, pos, start, len); + if (trimmedLen > 0) { + workArea.append(srcChars, pos, trimmedLen); + pos += trimmedLen; + continue; + } + + // copy regular character from outside quotes + workArea.append(srcChars[pos++]); + trimStart = workArea.size(); + } + } + + // return condition when end of string found + addToken(tokenList, workArea.substring(0, trimStart)); + return -1; + } + + /** + * Checks if the characters at the index specified match the quote + * already matched in readNextToken(). + * + * @param srcChars the character array being tokenized + * @param pos the position to check for a quote + * @param len the length of the character array being tokenized + * @param quoteStart the start position of the matched quote, 0 if no quoting + * @param quoteLen the length of the matched quote, 0 if no quoting + * @return true if a quote is matched + */ + private boolean isQuote(final char[] srcChars, final int pos, final int len, final int quoteStart, final int quoteLen) { + for (int i = 0; i < quoteLen; i++) { + if (pos + i >= len || srcChars[pos + i] != srcChars[quoteStart + i]) { + return false; + } + } + return true; + } + + // Delimiter + //----------------------------------------------------------------------- + /** + * Gets the field delimiter matcher. + * + * @return the delimiter matcher in use + */ + public StrMatcher getDelimiterMatcher() { + return this.delimMatcher; + } + + /** + * Sets the field delimiter matcher. + *

              + * The delimitier is used to separate one token from another. + * + * @param delim the delimiter matcher to use + * @return this, to enable chaining + */ + public StrTokenizer setDelimiterMatcher(final StrMatcher delim) { + if (delim == null) { + this.delimMatcher = StrMatcher.noneMatcher(); + } else { + this.delimMatcher = delim; + } + return this; + } + + /** + * Sets the field delimiter character. + * + * @param delim the delimiter character to use + * @return this, to enable chaining + */ + public StrTokenizer setDelimiterChar(final char delim) { + return setDelimiterMatcher(StrMatcher.charMatcher(delim)); + } + + /** + * Sets the field delimiter string. + * + * @param delim the delimiter string to use + * @return this, to enable chaining + */ + public StrTokenizer setDelimiterString(final String delim) { + return setDelimiterMatcher(StrMatcher.stringMatcher(delim)); + } + + // Quote + //----------------------------------------------------------------------- + /** + * Gets the quote matcher currently in use. + *

              + * The quote character is used to wrap data between the tokens. + * This enables delimiters to be entered as data. + * The default value is '"' (double quote). + * + * @return the quote matcher in use + */ + public StrMatcher getQuoteMatcher() { + return quoteMatcher; + } + + /** + * Set the quote matcher to use. + *

              + * The quote character is used to wrap data between the tokens. + * This enables delimiters to be entered as data. + * + * @param quote the quote matcher to use, null ignored + * @return this, to enable chaining + */ + public StrTokenizer setQuoteMatcher(final StrMatcher quote) { + if (quote != null) { + this.quoteMatcher = quote; + } + return this; + } + + /** + * Sets the quote character to use. + *

              + * The quote character is used to wrap data between the tokens. + * This enables delimiters to be entered as data. + * + * @param quote the quote character to use + * @return this, to enable chaining + */ + public StrTokenizer setQuoteChar(final char quote) { + return setQuoteMatcher(StrMatcher.charMatcher(quote)); + } + + // Ignored + //----------------------------------------------------------------------- + /** + * Gets the ignored character matcher. + *

              + * These characters are ignored when parsing the String, unless they are + * within a quoted region. + * The default value is not to ignore anything. + * + * @return the ignored matcher in use + */ + public StrMatcher getIgnoredMatcher() { + return ignoredMatcher; + } + + /** + * Set the matcher for characters to ignore. + *

              + * These characters are ignored when parsing the String, unless they are + * within a quoted region. + * + * @param ignored the ignored matcher to use, null ignored + * @return this, to enable chaining + */ + public StrTokenizer setIgnoredMatcher(final StrMatcher ignored) { + if (ignored != null) { + this.ignoredMatcher = ignored; + } + return this; + } + + /** + * Set the character to ignore. + *

              + * This character is ignored when parsing the String, unless it is + * within a quoted region. + * + * @param ignored the ignored character to use + * @return this, to enable chaining + */ + public StrTokenizer setIgnoredChar(final char ignored) { + return setIgnoredMatcher(StrMatcher.charMatcher(ignored)); + } + + // Trimmer + //----------------------------------------------------------------------- + /** + * Gets the trimmer character matcher. + *

              + * These characters are trimmed off on each side of the delimiter + * until the token or quote is found. + * The default value is not to trim anything. + * + * @return the trimmer matcher in use + */ + public StrMatcher getTrimmerMatcher() { + return trimmerMatcher; + } + + /** + * Sets the matcher for characters to trim. + *

              + * These characters are trimmed off on each side of the delimiter + * until the token or quote is found. + * + * @param trimmer the trimmer matcher to use, null ignored + * @return this, to enable chaining + */ + public StrTokenizer setTrimmerMatcher(final StrMatcher trimmer) { + if (trimmer != null) { + this.trimmerMatcher = trimmer; + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets whether the tokenizer currently returns empty tokens as null. + * The default for this property is false. + * + * @return true if empty tokens are returned as null + */ + public boolean isEmptyTokenAsNull() { + return this.emptyAsNull; + } + + /** + * Sets whether the tokenizer should return empty tokens as null. + * The default for this property is false. + * + * @param emptyAsNull whether empty tokens are returned as null + * @return this, to enable chaining + */ + public StrTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) { + this.emptyAsNull = emptyAsNull; + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets whether the tokenizer currently ignores empty tokens. + * The default for this property is true. + * + * @return true if empty tokens are not returned + */ + public boolean isIgnoreEmptyTokens() { + return ignoreEmptyTokens; + } + + /** + * Sets whether the tokenizer should ignore and not return empty tokens. + * The default for this property is true. + * + * @param ignoreEmptyTokens whether empty tokens are not returned + * @return this, to enable chaining + */ + public StrTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) { + this.ignoreEmptyTokens = ignoreEmptyTokens; + return this; + } + + //----------------------------------------------------------------------- + /** + * Gets the String content that the tokenizer is parsing. + * + * @return the string content being parsed + */ + public String getContent() { + if (chars == null) { + return null; + } + return new String(chars); + } + + //----------------------------------------------------------------------- + /** + * Creates a new instance of this Tokenizer. The new instance is reset so + * that it will be at the start of the token list. + * If a {@link CloneNotSupportedException} is caught, return null. + * + * @return a new instance of this Tokenizer which has been reset. + */ + @Override + public Object clone() { + try { + return cloneReset(); + } catch (final CloneNotSupportedException ex) { + return null; + } + } + + /** + * Creates a new instance of this Tokenizer. The new instance is reset so that + * it will be at the start of the token list. + * + * @return a new instance of this Tokenizer which has been reset. + * @throws CloneNotSupportedException if there is a problem cloning + */ + Object cloneReset() throws CloneNotSupportedException { + // this method exists to enable 100% test coverage + final StrTokenizer cloned = (StrTokenizer) super.clone(); + if (cloned.chars != null) { + cloned.chars = cloned.chars.clone(); + } + cloned.reset(); + return cloned; + } + + //----------------------------------------------------------------------- + /** + * Gets the String content that the tokenizer is parsing. + * + * @return the string content being parsed + */ + @Override + public String toString() { + if (tokens == null) { + return "StrTokenizer[not tokenized yet]"; + } + return "StrTokenizer" + getTokenList(); + } + +} diff --git a/src/org/apache/commons/lang3/text/WordUtils.java b/src/org/apache/commons/lang3/text/WordUtils.java new file mode 100644 index 0000000..0f6f363 --- /dev/null +++ b/src/org/apache/commons/lang3/text/WordUtils.java @@ -0,0 +1,736 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +/** + *

              Operations on Strings that contain words.

              + * + *

              This class tries to handle null input gracefully. + * An exception will not be thrown for a null input. + * Each method documents its behaviour in more detail.

              + * + * @since 2.0 + */ +public class WordUtils { + + /** + *

              WordUtils instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * WordUtils.wrap("foo bar", 20);.

              + * + *

              This constructor is public to permit tools that require a JavaBean + * instance to operate.

              + */ + public WordUtils() { + super(); + } + + // Wrapping + //-------------------------------------------------------------------------- + /** + *

              Wraps a single line of text, identifying words by ' '.

              + * + *

              New lines will be separated by the system property line separator. + * Very long words, such as URLs will not be wrapped.

              + * + *

              Leading spaces on a new line are stripped. + * Trailing spaces are not stripped.

              + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
              inputwrapLengthresult
              null*null
              ""*""
              "Here is one line of text that is going to be wrapped after 20 columns."20"Here is one line of\ntext that is going\nto be wrapped after\n20 columns."
              "Click here to jump to the commons website - http://commons.apache.org"20"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apache.org"
              "Click here, http://commons.apache.org, to jump to the commons website"20"Click here,\nhttp://commons.apache.org,\nto jump to the\ncommons website"
              + * + * (assuming that '\n' is the systems line separator) + * + * @param str the String to be word wrapped, may be null + * @param wrapLength the column to wrap the words at, less than 1 is treated as 1 + * @return a line with newlines inserted, null if null input + */ + public static String wrap(final String str, final int wrapLength) { + return wrap(str, wrapLength, null, false); + } + + /** + *

              Wraps a single line of text, identifying words by ' '.

              + * + *

              Leading spaces on a new line are stripped. + * Trailing spaces are not stripped.

              + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
              inputwrapLengthnewLineStringwrapLongWordsresult
              null**true/falsenull
              ""**true/false""
              "Here is one line of text that is going to be wrapped after 20 columns."20"\n"true/false"Here is one line of\ntext that is going\nto be wrapped after\n20 columns."
              "Here is one line of text that is going to be wrapped after 20 columns."20"<br />"true/false"Here is one line of<br />text that is going<br />to be wrapped after<br />20 columns."
              "Here is one line of text that is going to be wrapped after 20 columns."20nulltrue/false"Here is one line of" + systemNewLine + "text that is going" + systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."
              "Click here to jump to the commons website - http://commons.apache.org"20"\n"false"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apache.org"
              "Click here to jump to the commons website - http://commons.apache.org"20"\n"true"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apach\ne.org"
              + * + * @param str the String to be word wrapped, may be null + * @param wrapLength the column to wrap the words at, less than 1 is treated as 1 + * @param newLineStr the string to insert for a new line, + * null uses the system property line separator + * @param wrapLongWords true if long words (such as URLs) should be wrapped + * @return a line with newlines inserted, null if null input + */ + public static String wrap(final String str, final int wrapLength, final String newLineStr, final boolean wrapLongWords) { + return wrap(str, wrapLength, newLineStr, wrapLongWords, " "); + } + + /** + *

              Wraps a single line of text, identifying words by wrapOn.

              + * + *

              Leading spaces on a new line are stripped. + * Trailing spaces are not stripped.

              + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
              inputwrapLengthnewLineStringwrapLongWordswrapOnresult
              null**true/false*null
              ""**true/false*""
              "Here is one line of text that is going to be wrapped after 20 columns."20"\n"true/false" ""Here is one line of\ntext that is going\nto be wrapped after\n20 columns."
              "Here is one line of text that is going to be wrapped after 20 columns."20"<br />"true/false" ""Here is one line of<br />text that is going<br />to be wrapped after<br />20 columns."
              "Here is one line of text that is going to be wrapped after 20 columns."20nulltrue/false" ""Here is one line of" + systemNewLine + "text that is going" + systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."
              "Click here to jump to the commons website - http://commons.apache.org"20"\n"false" ""Click here to jump\nto the commons\nwebsite -\nhttp://commons.apache.org"
              "Click here to jump to the commons website - http://commons.apache.org"20"\n"true" ""Click here to jump\nto the commons\nwebsite -\nhttp://commons.apach\ne.org"
              "flammable/inflammable"20"\n"true"/""flammable\ninflammable"
              + * @param str the String to be word wrapped, may be null + * @param wrapLength the column to wrap the words at, less than 1 is treated as 1 + * @param newLineStr the string to insert for a new line, + * null uses the system property line separator + * @param wrapLongWords true if long words (such as URLs) should be wrapped + * @param wrapOn regex expression to be used as a breakable characters, + * if blank string is provided a space character will be used + * @return a line with newlines inserted, null if null input + */ + public static String wrap(final String str, int wrapLength, String newLineStr, final boolean wrapLongWords, String wrapOn) { + if (str == null) { + return null; + } + if (newLineStr == null) { + newLineStr = System.lineSeparator(); + } + if (wrapLength < 1) { + wrapLength = 1; + } + if (StringUtils.isBlank(wrapOn)) { + wrapOn = " "; + } + final Pattern patternToWrapOn = Pattern.compile(wrapOn); + final int inputLineLength = str.length(); + int offset = 0; + final StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32); + + while (offset < inputLineLength) { + int spaceToWrapAt = -1; + Matcher matcher = patternToWrapOn.matcher(str.substring(offset, Math.min(offset + wrapLength + 1, inputLineLength))); + if (matcher.find()) { + if (matcher.start() == 0) { + offset += matcher.end(); + continue; + }else { + spaceToWrapAt = matcher.start() + offset; + } + } + + // only last line without leading spaces is left + if(inputLineLength - offset <= wrapLength) { + break; + } + + while(matcher.find()){ + spaceToWrapAt = matcher.start() + offset; + } + + if (spaceToWrapAt >= offset) { + // normal case + wrappedLine.append(str.substring(offset, spaceToWrapAt)); + wrappedLine.append(newLineStr); + offset = spaceToWrapAt + 1; + + } else { + // really long word or URL + if (wrapLongWords) { + // wrap really long word one line at a time + wrappedLine.append(str.substring(offset, wrapLength + offset)); + wrappedLine.append(newLineStr); + offset += wrapLength; + } else { + // do not wrap really long word, just extend beyond limit + matcher = patternToWrapOn.matcher(str.substring(offset + wrapLength)); + if (matcher.find()) { + spaceToWrapAt = matcher.start() + offset + wrapLength; + } + + if (spaceToWrapAt >= 0) { + wrappedLine.append(str.substring(offset, spaceToWrapAt)); + wrappedLine.append(newLineStr); + offset = spaceToWrapAt + 1; + } else { + wrappedLine.append(str.substring(offset)); + offset = inputLineLength; + } + } + } + } + + // Whatever is left in line is short enough to just pass through + wrappedLine.append(str.substring(offset)); + + return wrappedLine.toString(); + } + + // Capitalizing + //----------------------------------------------------------------------- + /** + *

              Capitalizes all the whitespace separated words in a String. + * Only the first character of each word is changed. To convert the + * rest of each word to lowercase at the same time, + * use {@link #capitalizeFully(String)}.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}. + * A null input String returns null. + * Capitalization uses the Unicode title case, normally equivalent to + * upper case.

              + * + *
              +     * WordUtils.capitalize(null)        = null
              +     * WordUtils.capitalize("")          = ""
              +     * WordUtils.capitalize("i am FINE") = "I Am FINE"
              +     * 
              + * + * @param str the String to capitalize, may be null + * @return capitalized String, null if null String input + * @see #uncapitalize(String) + * @see #capitalizeFully(String) + */ + public static String capitalize(final String str) { + return capitalize(str, null); + } + + /** + *

              Capitalizes all the delimiter separated words in a String. + * Only the first character of each word is changed. To convert the + * rest of each word to lowercase at the same time, + * use {@link #capitalizeFully(String, char[])}.

              + * + *

              The delimiters represent a set of characters understood to separate words. + * The first string character and the first non-delimiter character after a + * delimiter will be capitalized.

              + * + *

              A null input String returns null. + * Capitalization uses the Unicode title case, normally equivalent to + * upper case.

              + * + *
              +     * WordUtils.capitalize(null, *)            = null
              +     * WordUtils.capitalize("", *)              = ""
              +     * WordUtils.capitalize(*, new char[0])     = *
              +     * WordUtils.capitalize("i am fine", null)  = "I Am Fine"
              +     * WordUtils.capitalize("i aM.fine", {'.'}) = "I aM.Fine"
              +     * 
              + * + * @param str the String to capitalize, may be null + * @param delimiters set of characters to determine capitalization, null means whitespace + * @return capitalized String, null if null String input + * @see #uncapitalize(String) + * @see #capitalizeFully(String) + * @since 2.1 + */ + public static String capitalize(final String str, final char... delimiters) { + final int delimLen = delimiters == null ? -1 : delimiters.length; + if (StringUtils.isEmpty(str) || delimLen == 0) { + return str; + } + final char[] buffer = str.toCharArray(); + boolean capitalizeNext = true; + for (int i = 0; i < buffer.length; i++) { + final char ch = buffer[i]; + if (isDelimiter(ch, delimiters)) { + capitalizeNext = true; + } else if (capitalizeNext) { + buffer[i] = Character.toTitleCase(ch); + capitalizeNext = false; + } + } + return new String(buffer); + } + + //----------------------------------------------------------------------- + /** + *

              Converts all the whitespace separated words in a String into capitalized words, + * that is each word is made up of a titlecase character and then a series of + * lowercase characters.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}. + * A null input String returns null. + * Capitalization uses the Unicode title case, normally equivalent to + * upper case.

              + * + *
              +     * WordUtils.capitalizeFully(null)        = null
              +     * WordUtils.capitalizeFully("")          = ""
              +     * WordUtils.capitalizeFully("i am FINE") = "I Am Fine"
              +     * 
              + * + * @param str the String to capitalize, may be null + * @return capitalized String, null if null String input + */ + public static String capitalizeFully(final String str) { + return capitalizeFully(str, null); + } + + /** + *

              Converts all the delimiter separated words in a String into capitalized words, + * that is each word is made up of a titlecase character and then a series of + * lowercase characters.

              + * + *

              The delimiters represent a set of characters understood to separate words. + * The first string character and the first non-delimiter character after a + * delimiter will be capitalized.

              + * + *

              A null input String returns null. + * Capitalization uses the Unicode title case, normally equivalent to + * upper case.

              + * + *
              +     * WordUtils.capitalizeFully(null, *)            = null
              +     * WordUtils.capitalizeFully("", *)              = ""
              +     * WordUtils.capitalizeFully(*, null)            = *
              +     * WordUtils.capitalizeFully(*, new char[0])     = *
              +     * WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine"
              +     * 
              + * + * @param str the String to capitalize, may be null + * @param delimiters set of characters to determine capitalization, null means whitespace + * @return capitalized String, null if null String input + * @since 2.1 + */ + public static String capitalizeFully(String str, final char... delimiters) { + final int delimLen = delimiters == null ? -1 : delimiters.length; + if (StringUtils.isEmpty(str) || delimLen == 0) { + return str; + } + str = str.toLowerCase(); + return capitalize(str, delimiters); + } + + //----------------------------------------------------------------------- + /** + *

              Uncapitalizes all the whitespace separated words in a String. + * Only the first character of each word is changed.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}. + * A null input String returns null.

              + * + *
              +     * WordUtils.uncapitalize(null)        = null
              +     * WordUtils.uncapitalize("")          = ""
              +     * WordUtils.uncapitalize("I Am FINE") = "i am fINE"
              +     * 
              + * + * @param str the String to uncapitalize, may be null + * @return uncapitalized String, null if null String input + * @see #capitalize(String) + */ + public static String uncapitalize(final String str) { + return uncapitalize(str, null); + } + + /** + *

              Uncapitalizes all the whitespace separated words in a String. + * Only the first character of each word is changed.

              + * + *

              The delimiters represent a set of characters understood to separate words. + * The first string character and the first non-delimiter character after a + * delimiter will be uncapitalized.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}. + * A null input String returns null.

              + * + *
              +     * WordUtils.uncapitalize(null, *)            = null
              +     * WordUtils.uncapitalize("", *)              = ""
              +     * WordUtils.uncapitalize(*, null)            = *
              +     * WordUtils.uncapitalize(*, new char[0])     = *
              +     * WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE"
              +     * 
              + * + * @param str the String to uncapitalize, may be null + * @param delimiters set of characters to determine uncapitalization, null means whitespace + * @return uncapitalized String, null if null String input + * @see #capitalize(String) + * @since 2.1 + */ + public static String uncapitalize(final String str, final char... delimiters) { + final int delimLen = delimiters == null ? -1 : delimiters.length; + if (StringUtils.isEmpty(str) || delimLen == 0) { + return str; + } + final char[] buffer = str.toCharArray(); + boolean uncapitalizeNext = true; + for (int i = 0; i < buffer.length; i++) { + final char ch = buffer[i]; + if (isDelimiter(ch, delimiters)) { + uncapitalizeNext = true; + } else if (uncapitalizeNext) { + buffer[i] = Character.toLowerCase(ch); + uncapitalizeNext = false; + } + } + return new String(buffer); + } + + //----------------------------------------------------------------------- + /** + *

              Swaps the case of a String using a word based algorithm.

              + * + *
                + *
              • Upper case character converts to Lower case
              • + *
              • Title case character converts to Lower case
              • + *
              • Lower case character after Whitespace or at start converts to Title case
              • + *
              • Other Lower case character converts to Upper case
              • + *
              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}. + * A null input String returns null.

              + * + *
              +     * StringUtils.swapCase(null)                 = null
              +     * StringUtils.swapCase("")                   = ""
              +     * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
              +     * 
              + * + * @param str the String to swap case, may be null + * @return the changed String, null if null String input + */ + public static String swapCase(final String str) { + if (StringUtils.isEmpty(str)) { + return str; + } + final char[] buffer = str.toCharArray(); + + boolean whitespace = true; + + for (int i = 0; i < buffer.length; i++) { + final char ch = buffer[i]; + if (Character.isUpperCase(ch)) { + buffer[i] = Character.toLowerCase(ch); + whitespace = false; + } else if (Character.isTitleCase(ch)) { + buffer[i] = Character.toLowerCase(ch); + whitespace = false; + } else if (Character.isLowerCase(ch)) { + if (whitespace) { + buffer[i] = Character.toTitleCase(ch); + whitespace = false; + } else { + buffer[i] = Character.toUpperCase(ch); + } + } else { + whitespace = Character.isWhitespace(ch); + } + } + return new String(buffer); + } + + //----------------------------------------------------------------------- + /** + *

              Extracts the initial characters from each word in the String.

              + * + *

              All first characters after whitespace are returned as a new string. + * Their case is not changed.

              + * + *

              Whitespace is defined by {@link Character#isWhitespace(char)}. + * A null input String returns null.

              + * + *
              +     * WordUtils.initials(null)             = null
              +     * WordUtils.initials("")               = ""
              +     * WordUtils.initials("Ben John Lee")   = "BJL"
              +     * WordUtils.initials("Ben J.Lee")      = "BJ"
              +     * 
              + * + * @param str the String to get initials from, may be null + * @return String of initial letters, null if null String input + * @see #initials(String,char[]) + * @since 2.2 + */ + public static String initials(final String str) { + return initials(str, null); + } + + /** + *

              Extracts the initial characters from each word in the String.

              + * + *

              All first characters after the defined delimiters are returned as a new string. + * Their case is not changed.

              + * + *

              If the delimiters array is null, then Whitespace is used. + * Whitespace is defined by {@link Character#isWhitespace(char)}. + * A null input String returns null. + * An empty delimiter array returns an empty String.

              + * + *
              +     * WordUtils.initials(null, *)                = null
              +     * WordUtils.initials("", *)                  = ""
              +     * WordUtils.initials("Ben John Lee", null)   = "BJL"
              +     * WordUtils.initials("Ben J.Lee", null)      = "BJ"
              +     * WordUtils.initials("Ben J.Lee", [' ','.']) = "BJL"
              +     * WordUtils.initials(*, new char[0])         = ""
              +     * 
              + * + * @param str the String to get initials from, may be null + * @param delimiters set of characters to determine words, null means whitespace + * @return String of initial characters, null if null String input + * @see #initials(String) + * @since 2.2 + */ + public static String initials(final String str, final char... delimiters) { + if (StringUtils.isEmpty(str)) { + return str; + } + if (delimiters != null && delimiters.length == 0) { + return StringUtils.EMPTY; + } + final int strLen = str.length(); + final char[] buf = new char[strLen / 2 + 1]; + int count = 0; + boolean lastWasGap = true; + for (int i = 0; i < strLen; i++) { + final char ch = str.charAt(i); + + if (isDelimiter(ch, delimiters)) { + lastWasGap = true; + } else if (lastWasGap) { + buf[count++] = ch; + lastWasGap = false; + } else { + continue; // ignore ch + } + } + return new String(buf, 0, count); + } + + //----------------------------------------------------------------------- + /** + *

              Checks if the String contains all words in the given array.

              + * + *

              + * A {@code null} String will return {@code false}. A {@code null}, zero + * length search array or if one element of array is null will return {@code false}. + *

              + * + *
              +     * WordUtils.containsAllWords(null, *)            = false
              +     * WordUtils.containsAllWords("", *)              = false
              +     * WordUtils.containsAllWords(*, null)            = false
              +     * WordUtils.containsAllWords(*, [])              = false
              +     * WordUtils.containsAllWords("abcd", "ab", "cd") = false
              +     * WordUtils.containsAllWords("abc def", "def", "abc") = true
              +     * 
              + * + * + * @param word The CharSequence to check, may be null + * @param words The array of String words to search for, may be null + * @return {@code true} if all search words are found, {@code false} otherwise + * @since 3.5 + */ + public static boolean containsAllWords(final CharSequence word, final CharSequence... words) { + if (StringUtils.isEmpty(word) || ArrayUtils.isEmpty(words)) { + return false; + } + for (final CharSequence w : words) { + if (StringUtils.isBlank(w)) { + return false; + } + final Pattern p = Pattern.compile(".*\\b" + w + "\\b.*"); + if (!p.matcher(word).matches()) { + return false; + } + } + return true; + } + + //----------------------------------------------------------------------- + /** + * Is the character a delimiter. + * + * @param ch the character to check + * @param delimiters the delimiters + * @return true if it is a delimiter + */ + private static boolean isDelimiter(final char ch, final char[] delimiters) { + if (delimiters == null) { + return Character.isWhitespace(ch); + } + for (final char delimiter : delimiters) { + if (ch == delimiter) { + return true; + } + } + return false; + } + +} diff --git a/src/org/apache/commons/lang3/text/package-info.java b/src/org/apache/commons/lang3/text/package-info.java new file mode 100644 index 0000000..61e4b05 --- /dev/null +++ b/src/org/apache/commons/lang3/text/package-info.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + *

              Provides classes for handling and manipulating text, partly as an extension to {@link java.text}. + * The classes in this package are, for the most part, intended to be instantiated (i.e. they are not utility classes + * with lots of static methods).

              + * + *

              Amongst other classes, the text package provides a replacement for {@link java.lang.StringBuffer} named {@link org.apache.commons.lang3.text.StrBuilder}, a class for substituting variables within a String named {@link org.apache.commons.lang3.text.StrSubstitutor} and a replacement for {@link java.util.StringTokenizer} named {@link org.apache.commons.lang3.text.StrTokenizer}. + * While somewhat ungainly, the Str prefix has been used to ensure we don't clash with any current or future standard Java classes.

              + * + * @since 2.1 + */ +package org.apache.commons.lang3.text; diff --git a/src/org/apache/commons/lang3/text/translate/AggregateTranslator.java b/src/org/apache/commons/lang3/text/translate/AggregateTranslator.java new file mode 100644 index 0000000..6f4519c --- /dev/null +++ b/src/org/apache/commons/lang3/text/translate/AggregateTranslator.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.Writer; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Executes a sequence of translators one after the other. Execution ends whenever + * the first translator consumes codepoints from the input. + * + * @since 3.0 + * @deprecated as of 3.6, use commons-text + * + * AggregateTranslator instead + */ +@Deprecated +public class AggregateTranslator extends CharSequenceTranslator { + + private final CharSequenceTranslator[] translators; + + /** + * Specify the translators to be used at creation time. + * + * @param translators CharSequenceTranslator array to aggregate + */ + public AggregateTranslator(final CharSequenceTranslator... translators) { + this.translators = ArrayUtils.clone(translators); + } + + /** + * The first translator to consume codepoints from the input is the 'winner'. + * Execution stops with the number of consumed codepoints being returned. + * {@inheritDoc} + */ + @Override + public int translate(final CharSequence input, final int index, final Writer out) throws IOException { + for (final CharSequenceTranslator translator : translators) { + final int consumed = translator.translate(input, index, out); + if(consumed != 0) { + return consumed; + } + } + return 0; + } + +} diff --git a/src/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java b/src/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java new file mode 100644 index 0000000..17fb8ac --- /dev/null +++ b/src/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Locale; + +/** + * An API for translating text. + * Its core use is to escape and unescape text. Because escaping and unescaping + * is completely contextual, the API does not present two separate signatures. + * + * @since 3.0 + * @deprecated as of 3.6, use commons-text + * + * CharSequenceTranslator instead + */ +@Deprecated +public abstract class CharSequenceTranslator { + + static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + /** + * Translate a set of codepoints, represented by an int index into a CharSequence, + * into another set of codepoints. The number of codepoints consumed must be returned, + * and the only IOExceptions thrown must be from interacting with the Writer so that + * the top level API may reliably ignore StringWriter IOExceptions. + * + * @param input CharSequence that is being translated + * @param index int representing the current point of translation + * @param out Writer to translate the text to + * @return int count of codepoints consumed + * @throws IOException if and only if the Writer produces an IOException + */ + public abstract int translate(CharSequence input, int index, Writer out) throws IOException; + + /** + * Helper for non-Writer usage. + * @param input CharSequence to be translated + * @return String output of translation + */ + public final String translate(final CharSequence input) { + if (input == null) { + return null; + } + try { + final StringWriter writer = new StringWriter(input.length() * 2); + translate(input, writer); + return writer.toString(); + } catch (final IOException ioe) { + // this should never ever happen while writing to a StringWriter + throw new RuntimeException(ioe); + } + } + + /** + * Translate an input onto a Writer. This is intentionally final as its algorithm is + * tightly coupled with the abstract method of this class. + * + * @param input CharSequence that is being translated + * @param out Writer to translate the text to + * @throws IOException if and only if the Writer produces an IOException + */ + public final void translate(final CharSequence input, final Writer out) throws IOException { + if (out == null) { + throw new IllegalArgumentException("The Writer must not be null"); + } + if (input == null) { + return; + } + int pos = 0; + final int len = input.length(); + while (pos < len) { + final int consumed = translate(input, pos, out); + if (consumed == 0) { + // inlined implementation of Character.toChars(Character.codePointAt(input, pos)) + // avoids allocating temp char arrays and duplicate checks + final char c1 = input.charAt(pos); + out.write(c1); + pos++; + if (Character.isHighSurrogate(c1) && pos < len) { + final char c2 = input.charAt(pos); + if (Character.isLowSurrogate(c2)) { + out.write(c2); + pos++; + } + } + continue; + } + // contract with translators is that they have to understand codepoints + // and they just took care of a surrogate pair + for (int pt = 0; pt < consumed; pt++) { + pos += Character.charCount(Character.codePointAt(input, pos)); + } + } + } + + /** + * Helper method to create a merger of this translator with another set of + * translators. Useful in customizing the standard functionality. + * + * @param translators CharSequenceTranslator array of translators to merge with this one + * @return CharSequenceTranslator merging this translator with the others + */ + public final CharSequenceTranslator with(final CharSequenceTranslator... translators) { + final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1]; + newArray[0] = this; + System.arraycopy(translators, 0, newArray, 1, translators.length); + return new AggregateTranslator(newArray); + } + + /** + *

              Returns an upper case hexadecimal String for the given + * character.

              + * + * @param codepoint The codepoint to convert. + * @return An upper case hexadecimal String + */ + public static String hex(final int codepoint) { + return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH); + } + +} diff --git a/src/org/apache/commons/lang3/text/translate/CodePointTranslator.java b/src/org/apache/commons/lang3/text/translate/CodePointTranslator.java new file mode 100644 index 0000000..92ed505 --- /dev/null +++ b/src/org/apache/commons/lang3/text/translate/CodePointTranslator.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.Writer; + +/** + * Helper subclass to CharSequenceTranslator to allow for translations that + * will replace up to one character at a time. + * + * @since 3.0 + * @deprecated as of 3.6, use commons-text + * + * CharSequenceTranslator instead + */ +@Deprecated +public abstract class CodePointTranslator extends CharSequenceTranslator { + + /** + * Implementation of translate that maps onto the abstract translate(int, Writer) method. + * {@inheritDoc} + */ + @Override + public final int translate(final CharSequence input, final int index, final Writer out) throws IOException { + final int codepoint = Character.codePointAt(input, index); + final boolean consumed = translate(codepoint, out); + return consumed ? 1 : 0; + } + + /** + * Translate the specified codepoint into another. + * + * @param codepoint int character input to translate + * @param out Writer to optionally push the translated output to + * @return boolean as to whether translation occurred or not + * @throws IOException if and only if the Writer produces an IOException + */ + public abstract boolean translate(int codepoint, Writer out) throws IOException; + +} diff --git a/src/org/apache/commons/lang3/text/translate/EntityArrays.java b/src/org/apache/commons/lang3/text/translate/EntityArrays.java new file mode 100644 index 0000000..093d056 --- /dev/null +++ b/src/org/apache/commons/lang3/text/translate/EntityArrays.java @@ -0,0 +1,428 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text.translate; + +/** + * Class holding various entity data for HTML and XML - generally for use with + * the LookupTranslator. + * All arrays are of length [*][2]. + * + * @since 3.0 + * @deprecated as of 3.6, use commons-text + * + * EntityArrays instead + */ +@Deprecated +public class EntityArrays { + + /** + * Mapping to escape ISO-8859-1 + * characters to their named HTML 3.x equivalents. + * @return the mapping table + */ + public static String[][] ISO8859_1_ESCAPE() { return ISO8859_1_ESCAPE.clone(); } + private static final String[][] ISO8859_1_ESCAPE = { + {"\u00A0", " "}, // non-breaking space + {"\u00A1", "¡"}, // inverted exclamation mark + {"\u00A2", "¢"}, // cent sign + {"\u00A3", "£"}, // pound sign + {"\u00A4", "¤"}, // currency sign + {"\u00A5", "¥"}, // yen sign = yuan sign + {"\u00A6", "¦"}, // broken bar = broken vertical bar + {"\u00A7", "§"}, // section sign + {"\u00A8", "¨"}, // diaeresis = spacing diaeresis + {"\u00A9", "©"}, // © - copyright sign + {"\u00AA", "ª"}, // feminine ordinal indicator + {"\u00AB", "«"}, // left-pointing double angle quotation mark = left pointing guillemet + {"\u00AC", "¬"}, // not sign + {"\u00AD", "­"}, // soft hyphen = discretionary hyphen + {"\u00AE", "®"}, // ® - registered trademark sign + {"\u00AF", "¯"}, // macron = spacing macron = overline = APL overbar + {"\u00B0", "°"}, // degree sign + {"\u00B1", "±"}, // plus-minus sign = plus-or-minus sign + {"\u00B2", "²"}, // superscript two = superscript digit two = squared + {"\u00B3", "³"}, // superscript three = superscript digit three = cubed + {"\u00B4", "´"}, // acute accent = spacing acute + {"\u00B5", "µ"}, // micro sign + {"\u00B6", "¶"}, // pilcrow sign = paragraph sign + {"\u00B7", "·"}, // middle dot = Georgian comma = Greek middle dot + {"\u00B8", "¸"}, // cedilla = spacing cedilla + {"\u00B9", "¹"}, // superscript one = superscript digit one + {"\u00BA", "º"}, // masculine ordinal indicator + {"\u00BB", "»"}, // right-pointing double angle quotation mark = right pointing guillemet + {"\u00BC", "¼"}, // vulgar fraction one quarter = fraction one quarter + {"\u00BD", "½"}, // vulgar fraction one half = fraction one half + {"\u00BE", "¾"}, // vulgar fraction three quarters = fraction three quarters + {"\u00BF", "¿"}, // inverted question mark = turned question mark + {"\u00C0", "À"}, // À - uppercase A, grave accent + {"\u00C1", "Á"}, // Ã? - uppercase A, acute accent + {"\u00C2", "Â"}, //  - uppercase A, circumflex accent + {"\u00C3", "Ã"}, // à - uppercase A, tilde + {"\u00C4", "Ä"}, // Ä - uppercase A, umlaut + {"\u00C5", "Å"}, // Ã… - uppercase A, ring + {"\u00C6", "Æ"}, // Æ - uppercase AE + {"\u00C7", "Ç"}, // Ç - uppercase C, cedilla + {"\u00C8", "È"}, // È - uppercase E, grave accent + {"\u00C9", "É"}, // É - uppercase E, acute accent + {"\u00CA", "Ê"}, // Ê - uppercase E, circumflex accent + {"\u00CB", "Ë"}, // Ë - uppercase E, umlaut + {"\u00CC", "Ì"}, // ÃŒ - uppercase I, grave accent + {"\u00CD", "Í"}, // Ã? - uppercase I, acute accent + {"\u00CE", "Î"}, // ÃŽ - uppercase I, circumflex accent + {"\u00CF", "Ï"}, // Ã? - uppercase I, umlaut + {"\u00D0", "Ð"}, // Ã? - uppercase Eth, Icelandic + {"\u00D1", "Ñ"}, // Ñ - uppercase N, tilde + {"\u00D2", "Ò"}, // Ã’ - uppercase O, grave accent + {"\u00D3", "Ó"}, // Ó - uppercase O, acute accent + {"\u00D4", "Ô"}, // Ô - uppercase O, circumflex accent + {"\u00D5", "Õ"}, // Õ - uppercase O, tilde + {"\u00D6", "Ö"}, // Ö - uppercase O, umlaut + {"\u00D7", "×"}, // multiplication sign + {"\u00D8", "Ø"}, // Ø - uppercase O, slash + {"\u00D9", "Ù"}, // Ù - uppercase U, grave accent + {"\u00DA", "Ú"}, // Ú - uppercase U, acute accent + {"\u00DB", "Û"}, // Û - uppercase U, circumflex accent + {"\u00DC", "Ü"}, // Ãœ - uppercase U, umlaut + {"\u00DD", "Ý"}, // Ã? - uppercase Y, acute accent + {"\u00DE", "Þ"}, // Þ - uppercase THORN, Icelandic + {"\u00DF", "ß"}, // ß - lowercase sharps, German + {"\u00E0", "à"}, // à - lowercase a, grave accent + {"\u00E1", "á"}, // á - lowercase a, acute accent + {"\u00E2", "â"}, // â - lowercase a, circumflex accent + {"\u00E3", "ã"}, // ã - lowercase a, tilde + {"\u00E4", "ä"}, // ä - lowercase a, umlaut + {"\u00E5", "å"}, // Ã¥ - lowercase a, ring + {"\u00E6", "æ"}, // æ - lowercase ae + {"\u00E7", "ç"}, // ç - lowercase c, cedilla + {"\u00E8", "è"}, // è - lowercase e, grave accent + {"\u00E9", "é"}, // é - lowercase e, acute accent + {"\u00EA", "ê"}, // ê - lowercase e, circumflex accent + {"\u00EB", "ë"}, // ë - lowercase e, umlaut + {"\u00EC", "ì"}, // ì - lowercase i, grave accent + {"\u00ED", "í"}, // í - lowercase i, acute accent + {"\u00EE", "î"}, // î - lowercase i, circumflex accent + {"\u00EF", "ï"}, // ï - lowercase i, umlaut + {"\u00F0", "ð"}, // ð - lowercase eth, Icelandic + {"\u00F1", "ñ"}, // ñ - lowercase n, tilde + {"\u00F2", "ò"}, // ò - lowercase o, grave accent + {"\u00F3", "ó"}, // ó - lowercase o, acute accent + {"\u00F4", "ô"}, // ô - lowercase o, circumflex accent + {"\u00F5", "õ"}, // õ - lowercase o, tilde + {"\u00F6", "ö"}, // ö - lowercase o, umlaut + {"\u00F7", "÷"}, // division sign + {"\u00F8", "ø"}, // ø - lowercase o, slash + {"\u00F9", "ù"}, // ù - lowercase u, grave accent + {"\u00FA", "ú"}, // ú - lowercase u, acute accent + {"\u00FB", "û"}, // û - lowercase u, circumflex accent + {"\u00FC", "ü"}, // ü - lowercase u, umlaut + {"\u00FD", "ý"}, // ý - lowercase y, acute accent + {"\u00FE", "þ"}, // þ - lowercase thorn, Icelandic + {"\u00FF", "ÿ"}, // ÿ - lowercase y, umlaut + }; + + /** + * Reverse of {@link #ISO8859_1_ESCAPE()} for unescaping purposes. + * @return the mapping table + */ + public static String[][] ISO8859_1_UNESCAPE() { return ISO8859_1_UNESCAPE.clone(); } + private static final String[][] ISO8859_1_UNESCAPE = invert(ISO8859_1_ESCAPE); + + /** + * Mapping to escape additional character entity + * references. Note that this must be used with {@link #ISO8859_1_ESCAPE()} to get the full list of + * HTML 4.0 character entities. + * @return the mapping table + */ + public static String[][] HTML40_EXTENDED_ESCAPE() { return HTML40_EXTENDED_ESCAPE.clone(); } + private static final String[][] HTML40_EXTENDED_ESCAPE = { + // + {"\u0192", "ƒ"}, // latin small f with hook = function= florin, U+0192 ISOtech --> + // + {"\u0391", "Α"}, // greek capital letter alpha, U+0391 --> + {"\u0392", "Β"}, // greek capital letter beta, U+0392 --> + {"\u0393", "Γ"}, // greek capital letter gamma,U+0393 ISOgrk3 --> + {"\u0394", "Δ"}, // greek capital letter delta,U+0394 ISOgrk3 --> + {"\u0395", "Ε"}, // greek capital letter epsilon, U+0395 --> + {"\u0396", "Ζ"}, // greek capital letter zeta, U+0396 --> + {"\u0397", "Η"}, // greek capital letter eta, U+0397 --> + {"\u0398", "Θ"}, // greek capital letter theta,U+0398 ISOgrk3 --> + {"\u0399", "Ι"}, // greek capital letter iota, U+0399 --> + {"\u039A", "Κ"}, // greek capital letter kappa, U+039A --> + {"\u039B", "Λ"}, // greek capital letter lambda,U+039B ISOgrk3 --> + {"\u039C", "Μ"}, // greek capital letter mu, U+039C --> + {"\u039D", "Ν"}, // greek capital letter nu, U+039D --> + {"\u039E", "Ξ"}, // greek capital letter xi, U+039E ISOgrk3 --> + {"\u039F", "Ο"}, // greek capital letter omicron, U+039F --> + {"\u03A0", "Π"}, // greek capital letter pi, U+03A0 ISOgrk3 --> + {"\u03A1", "Ρ"}, // greek capital letter rho, U+03A1 --> + // + {"\u03A3", "Σ"}, // greek capital letter sigma,U+03A3 ISOgrk3 --> + {"\u03A4", "Τ"}, // greek capital letter tau, U+03A4 --> + {"\u03A5", "Υ"}, // greek capital letter upsilon,U+03A5 ISOgrk3 --> + {"\u03A6", "Φ"}, // greek capital letter phi,U+03A6 ISOgrk3 --> + {"\u03A7", "Χ"}, // greek capital letter chi, U+03A7 --> + {"\u03A8", "Ψ"}, // greek capital letter psi,U+03A8 ISOgrk3 --> + {"\u03A9", "Ω"}, // greek capital letter omega,U+03A9 ISOgrk3 --> + {"\u03B1", "α"}, // greek small letter alpha,U+03B1 ISOgrk3 --> + {"\u03B2", "β"}, // greek small letter beta, U+03B2 ISOgrk3 --> + {"\u03B3", "γ"}, // greek small letter gamma,U+03B3 ISOgrk3 --> + {"\u03B4", "δ"}, // greek small letter delta,U+03B4 ISOgrk3 --> + {"\u03B5", "ε"}, // greek small letter epsilon,U+03B5 ISOgrk3 --> + {"\u03B6", "ζ"}, // greek small letter zeta, U+03B6 ISOgrk3 --> + {"\u03B7", "η"}, // greek small letter eta, U+03B7 ISOgrk3 --> + {"\u03B8", "θ"}, // greek small letter theta,U+03B8 ISOgrk3 --> + {"\u03B9", "ι"}, // greek small letter iota, U+03B9 ISOgrk3 --> + {"\u03BA", "κ"}, // greek small letter kappa,U+03BA ISOgrk3 --> + {"\u03BB", "λ"}, // greek small letter lambda,U+03BB ISOgrk3 --> + {"\u03BC", "μ"}, // greek small letter mu, U+03BC ISOgrk3 --> + {"\u03BD", "ν"}, // greek small letter nu, U+03BD ISOgrk3 --> + {"\u03BE", "ξ"}, // greek small letter xi, U+03BE ISOgrk3 --> + {"\u03BF", "ο"}, // greek small letter omicron, U+03BF NEW --> + {"\u03C0", "π"}, // greek small letter pi, U+03C0 ISOgrk3 --> + {"\u03C1", "ρ"}, // greek small letter rho, U+03C1 ISOgrk3 --> + {"\u03C2", "ς"}, // greek small letter final sigma,U+03C2 ISOgrk3 --> + {"\u03C3", "σ"}, // greek small letter sigma,U+03C3 ISOgrk3 --> + {"\u03C4", "τ"}, // greek small letter tau, U+03C4 ISOgrk3 --> + {"\u03C5", "υ"}, // greek small letter upsilon,U+03C5 ISOgrk3 --> + {"\u03C6", "φ"}, // greek small letter phi, U+03C6 ISOgrk3 --> + {"\u03C7", "χ"}, // greek small letter chi, U+03C7 ISOgrk3 --> + {"\u03C8", "ψ"}, // greek small letter psi, U+03C8 ISOgrk3 --> + {"\u03C9", "ω"}, // greek small letter omega,U+03C9 ISOgrk3 --> + {"\u03D1", "ϑ"}, // greek small letter theta symbol,U+03D1 NEW --> + {"\u03D2", "ϒ"}, // greek upsilon with hook symbol,U+03D2 NEW --> + {"\u03D6", "ϖ"}, // greek pi symbol, U+03D6 ISOgrk3 --> + // + {"\u2022", "•"}, // bullet = black small circle,U+2022 ISOpub --> + // + {"\u2026", "…"}, // horizontal ellipsis = three dot leader,U+2026 ISOpub --> + {"\u2032", "′"}, // prime = minutes = feet, U+2032 ISOtech --> + {"\u2033", "″"}, // double prime = seconds = inches,U+2033 ISOtech --> + {"\u203E", "‾"}, // overline = spacing overscore,U+203E NEW --> + {"\u2044", "⁄"}, // fraction slash, U+2044 NEW --> + // + {"\u2118", "℘"}, // script capital P = power set= Weierstrass p, U+2118 ISOamso --> + {"\u2111", "ℑ"}, // blackletter capital I = imaginary part,U+2111 ISOamso --> + {"\u211C", "ℜ"}, // blackletter capital R = real part symbol,U+211C ISOamso --> + {"\u2122", "™"}, // trade mark sign, U+2122 ISOnum --> + {"\u2135", "ℵ"}, // alef symbol = first transfinite cardinal,U+2135 NEW --> + // + // + {"\u2190", "←"}, // leftwards arrow, U+2190 ISOnum --> + {"\u2191", "↑"}, // upwards arrow, U+2191 ISOnum--> + {"\u2192", "→"}, // rightwards arrow, U+2192 ISOnum --> + {"\u2193", "↓"}, // downwards arrow, U+2193 ISOnum --> + {"\u2194", "↔"}, // left right arrow, U+2194 ISOamsa --> + {"\u21B5", "↵"}, // downwards arrow with corner leftwards= carriage return, U+21B5 NEW --> + {"\u21D0", "⇐"}, // leftwards double arrow, U+21D0 ISOtech --> + // + {"\u21D1", "⇑"}, // upwards double arrow, U+21D1 ISOamsa --> + {"\u21D2", "⇒"}, // rightwards double arrow,U+21D2 ISOtech --> + // + {"\u21D3", "⇓"}, // downwards double arrow, U+21D3 ISOamsa --> + {"\u21D4", "⇔"}, // left right double arrow,U+21D4 ISOamsa --> + // + {"\u2200", "∀"}, // for all, U+2200 ISOtech --> + {"\u2202", "∂"}, // partial differential, U+2202 ISOtech --> + {"\u2203", "∃"}, // there exists, U+2203 ISOtech --> + {"\u2205", "∅"}, // empty set = null set = diameter,U+2205 ISOamso --> + {"\u2207", "∇"}, // nabla = backward difference,U+2207 ISOtech --> + {"\u2208", "∈"}, // element of, U+2208 ISOtech --> + {"\u2209", "∉"}, // not an element of, U+2209 ISOtech --> + {"\u220B", "∋"}, // contains as member, U+220B ISOtech --> + // + {"\u220F", "∏"}, // n-ary product = product sign,U+220F ISOamsb --> + // + {"\u2211", "∑"}, // n-ary summation, U+2211 ISOamsb --> + // + {"\u2212", "−"}, // minus sign, U+2212 ISOtech --> + {"\u2217", "∗"}, // asterisk operator, U+2217 ISOtech --> + {"\u221A", "√"}, // square root = radical sign,U+221A ISOtech --> + {"\u221D", "∝"}, // proportional to, U+221D ISOtech --> + {"\u221E", "∞"}, // infinity, U+221E ISOtech --> + {"\u2220", "∠"}, // angle, U+2220 ISOamso --> + {"\u2227", "∧"}, // logical and = wedge, U+2227 ISOtech --> + {"\u2228", "∨"}, // logical or = vee, U+2228 ISOtech --> + {"\u2229", "∩"}, // intersection = cap, U+2229 ISOtech --> + {"\u222A", "∪"}, // union = cup, U+222A ISOtech --> + {"\u222B", "∫"}, // integral, U+222B ISOtech --> + {"\u2234", "∴"}, // therefore, U+2234 ISOtech --> + {"\u223C", "∼"}, // tilde operator = varies with = similar to,U+223C ISOtech --> + // + {"\u2245", "≅"}, // approximately equal to, U+2245 ISOtech --> + {"\u2248", "≈"}, // almost equal to = asymptotic to,U+2248 ISOamsr --> + {"\u2260", "≠"}, // not equal to, U+2260 ISOtech --> + {"\u2261", "≡"}, // identical to, U+2261 ISOtech --> + {"\u2264", "≤"}, // less-than or equal to, U+2264 ISOtech --> + {"\u2265", "≥"}, // greater-than or equal to,U+2265 ISOtech --> + {"\u2282", "⊂"}, // subset of, U+2282 ISOtech --> + {"\u2283", "⊃"}, // superset of, U+2283 ISOtech --> + // , + {"\u2284", "⊄"}, // not a subset of, U+2284 ISOamsn --> + {"\u2286", "⊆"}, // subset of or equal to, U+2286 ISOtech --> + {"\u2287", "⊇"}, // superset of or equal to,U+2287 ISOtech --> + {"\u2295", "⊕"}, // circled plus = direct sum,U+2295 ISOamsb --> + {"\u2297", "⊗"}, // circled times = vector product,U+2297 ISOamsb --> + {"\u22A5", "⊥"}, // up tack = orthogonal to = perpendicular,U+22A5 ISOtech --> + {"\u22C5", "⋅"}, // dot operator, U+22C5 ISOamsb --> + // + // + {"\u2308", "⌈"}, // left ceiling = apl upstile,U+2308 ISOamsc --> + {"\u2309", "⌉"}, // right ceiling, U+2309 ISOamsc --> + {"\u230A", "⌊"}, // left floor = apl downstile,U+230A ISOamsc --> + {"\u230B", "⌋"}, // right floor, U+230B ISOamsc --> + {"\u2329", "⟨"}, // left-pointing angle bracket = bra,U+2329 ISOtech --> + // + {"\u232A", "⟩"}, // right-pointing angle bracket = ket,U+232A ISOtech --> + // + // + {"\u25CA", "◊"}, // lozenge, U+25CA ISOpub --> + // + {"\u2660", "♠"}, // black spade suit, U+2660 ISOpub --> + // + {"\u2663", "♣"}, // black club suit = shamrock,U+2663 ISOpub --> + {"\u2665", "♥"}, // black heart suit = valentine,U+2665 ISOpub --> + {"\u2666", "♦"}, // black diamond suit, U+2666 ISOpub --> + + // + {"\u0152", "Œ"}, // -- latin capital ligature OE,U+0152 ISOlat2 --> + {"\u0153", "œ"}, // -- latin small ligature oe, U+0153 ISOlat2 --> + // + {"\u0160", "Š"}, // -- latin capital letter S with caron,U+0160 ISOlat2 --> + {"\u0161", "š"}, // -- latin small letter s with caron,U+0161 ISOlat2 --> + {"\u0178", "Ÿ"}, // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 --> + // + {"\u02C6", "ˆ"}, // -- modifier letter circumflex accent,U+02C6 ISOpub --> + {"\u02DC", "˜"}, // small tilde, U+02DC ISOdia --> + // + {"\u2002", " "}, // en space, U+2002 ISOpub --> + {"\u2003", " "}, // em space, U+2003 ISOpub --> + {"\u2009", " "}, // thin space, U+2009 ISOpub --> + {"\u200C", "‌"}, // zero width non-joiner,U+200C NEW RFC 2070 --> + {"\u200D", "‍"}, // zero width joiner, U+200D NEW RFC 2070 --> + {"\u200E", "‎"}, // left-to-right mark, U+200E NEW RFC 2070 --> + {"\u200F", "‏"}, // right-to-left mark, U+200F NEW RFC 2070 --> + {"\u2013", "–"}, // en dash, U+2013 ISOpub --> + {"\u2014", "—"}, // em dash, U+2014 ISOpub --> + {"\u2018", "‘"}, // left single quotation mark,U+2018 ISOnum --> + {"\u2019", "’"}, // right single quotation mark,U+2019 ISOnum --> + {"\u201A", "‚"}, // single low-9 quotation mark, U+201A NEW --> + {"\u201C", "“"}, // left double quotation mark,U+201C ISOnum --> + {"\u201D", "”"}, // right double quotation mark,U+201D ISOnum --> + {"\u201E", "„"}, // double low-9 quotation mark, U+201E NEW --> + {"\u2020", "†"}, // dagger, U+2020 ISOpub --> + {"\u2021", "‡"}, // double dagger, U+2021 ISOpub --> + {"\u2030", "‰"}, // per mille sign, U+2030 ISOtech --> + {"\u2039", "‹"}, // single left-pointing angle quotation mark,U+2039 ISO proposed --> + // + {"\u203A", "›"}, // single right-pointing angle quotation mark,U+203A ISO proposed --> + // + {"\u20AC", "€"}, // -- euro sign, U+20AC NEW --> + }; + + /** + * Reverse of {@link #HTML40_EXTENDED_ESCAPE()} for unescaping purposes. + * @return the mapping table + */ + public static String[][] HTML40_EXTENDED_UNESCAPE() { return HTML40_EXTENDED_UNESCAPE.clone(); } + private static final String[][] HTML40_EXTENDED_UNESCAPE = invert(HTML40_EXTENDED_ESCAPE); + + /** + * Mapping to escape the basic XML and HTML character entities. + * + * Namely: {@code " & < >} + * @return the mapping table + */ + public static String[][] BASIC_ESCAPE() { return BASIC_ESCAPE.clone(); } + private static final String[][] BASIC_ESCAPE = { + {"\"", """}, // " - double-quote + {"&", "&"}, // & - ampersand + {"<", "<"}, // < - less-than + {">", ">"}, // > - greater-than + }; + + /** + * Reverse of {@link #BASIC_ESCAPE()} for unescaping purposes. + * @return the mapping table + */ + public static String[][] BASIC_UNESCAPE() { return BASIC_UNESCAPE.clone(); } + private static final String[][] BASIC_UNESCAPE = invert(BASIC_ESCAPE); + + /** + * Mapping to escape the apostrophe character to its XML character entity. + * @return the mapping table + */ + public static String[][] APOS_ESCAPE() { return APOS_ESCAPE.clone(); } + private static final String[][] APOS_ESCAPE = { + {"'", "'"}, // XML apostrophe + }; + + /** + * Reverse of {@link #APOS_ESCAPE()} for unescaping purposes. + * @return the mapping table + */ + public static String[][] APOS_UNESCAPE() { return APOS_UNESCAPE.clone(); } + private static final String[][] APOS_UNESCAPE = invert(APOS_ESCAPE); + + /** + * Mapping to escape the Java control characters. + * + * Namely: {@code \b \n \t \f \r} + * @return the mapping table + */ + public static String[][] JAVA_CTRL_CHARS_ESCAPE() { return JAVA_CTRL_CHARS_ESCAPE.clone(); } + private static final String[][] JAVA_CTRL_CHARS_ESCAPE = { + {"\b", "\\b"}, + {"\n", "\\n"}, + {"\t", "\\t"}, + {"\f", "\\f"}, + {"\r", "\\r"} + }; + + /** + * Reverse of {@link #JAVA_CTRL_CHARS_ESCAPE()} for unescaping purposes. + * @return the mapping table + */ + public static String[][] JAVA_CTRL_CHARS_UNESCAPE() { return JAVA_CTRL_CHARS_UNESCAPE.clone(); } + private static final String[][] JAVA_CTRL_CHARS_UNESCAPE = invert(JAVA_CTRL_CHARS_ESCAPE); + + /** + * Used to invert an escape array into an unescape array + * @param array String[][] to be inverted + * @return String[][] inverted array + */ + public static String[][] invert(final String[][] array) { + final String[][] newarray = new String[array.length][2]; + for(int i = 0; i + * UnicodeEscaper instead + */ +@Deprecated +public class JavaUnicodeEscaper extends UnicodeEscaper { + + /** + *

              + * Constructs a JavaUnicodeEscaper above the specified value (exclusive). + *

              + * + * @param codepoint + * above which to escape + * @return the newly created {@code UnicodeEscaper} instance + */ + public static JavaUnicodeEscaper above(final int codepoint) { + return outsideOf(0, codepoint); + } + + /** + *

              + * Constructs a JavaUnicodeEscaper below the specified value (exclusive). + *

              + * + * @param codepoint + * below which to escape + * @return the newly created {@code UnicodeEscaper} instance + */ + public static JavaUnicodeEscaper below(final int codepoint) { + return outsideOf(codepoint, Integer.MAX_VALUE); + } + + /** + *

              + * Constructs a JavaUnicodeEscaper between the specified values (inclusive). + *

              + * + * @param codepointLow + * above which to escape + * @param codepointHigh + * below which to escape + * @return the newly created {@code UnicodeEscaper} instance + */ + public static JavaUnicodeEscaper between(final int codepointLow, final int codepointHigh) { + return new JavaUnicodeEscaper(codepointLow, codepointHigh, true); + } + + /** + *

              + * Constructs a JavaUnicodeEscaper outside of the specified values (exclusive). + *

              + * + * @param codepointLow + * below which to escape + * @param codepointHigh + * above which to escape + * @return the newly created {@code UnicodeEscaper} instance + */ + public static JavaUnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) { + return new JavaUnicodeEscaper(codepointLow, codepointHigh, false); + } + + /** + *

              + * Constructs a JavaUnicodeEscaper for the specified range. This is the underlying method for the + * other constructors/builders. The below and above boundaries are inclusive when + * between is true and exclusive when it is false. + *

              + * + * @param below + * int value representing the lowest codepoint boundary + * @param above + * int value representing the highest codepoint boundary + * @param between + * whether to escape between the boundaries or outside them + */ + public JavaUnicodeEscaper(final int below, final int above, final boolean between) { + super(below, above, between); + } + + /** + * Converts the given codepoint to a hex string of the form {@code "\\uXXXX\\uXXXX"} + * + * @param codepoint + * a Unicode code point + * @return the hex string for the given codepoint + */ + @Override + protected String toUtf16Escape(final int codepoint) { + final char[] surrogatePair = Character.toChars(codepoint); + return "\\u" + hex(surrogatePair[0]) + "\\u" + hex(surrogatePair[1]); + } + +} diff --git a/src/org/apache/commons/lang3/text/translate/LookupTranslator.java b/src/org/apache/commons/lang3/text/translate/LookupTranslator.java new file mode 100644 index 0000000..e00983e --- /dev/null +++ b/src/org/apache/commons/lang3/text/translate/LookupTranslator.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.HashSet; + +/** + * Translates a value using a lookup table. + * + * @since 3.0 + * @deprecated as of 3.6, use commons-text + * + * LookupTranslator instead + */ +@Deprecated +public class LookupTranslator extends CharSequenceTranslator { + + private final HashMap lookupMap; + private final HashSet prefixSet; + private final int shortest; + private final int longest; + + /** + * Define the lookup table to be used in translation + * + * Note that, as of Lang 3.1, the key to the lookup table is converted to a + * java.lang.String. This is because we need the key to support hashCode and + * equals(Object), allowing it to be the key for a HashMap. See LANG-882. + * + * @param lookup CharSequence[][] table of size [*][2] + */ + public LookupTranslator(final CharSequence[]... lookup) { + lookupMap = new HashMap<>(); + prefixSet = new HashSet<>(); + int _shortest = Integer.MAX_VALUE; + int _longest = 0; + if (lookup != null) { + for (final CharSequence[] seq : lookup) { + this.lookupMap.put(seq[0].toString(), seq[1].toString()); + this.prefixSet.add(seq[0].charAt(0)); + final int sz = seq[0].length(); + if (sz < _shortest) { + _shortest = sz; + } + if (sz > _longest) { + _longest = sz; + } + } + } + shortest = _shortest; + longest = _longest; + } + + /** + * {@inheritDoc} + */ + @Override + public int translate(final CharSequence input, final int index, final Writer out) throws IOException { + // check if translation exists for the input at position index + if (prefixSet.contains(input.charAt(index))) { + int max = longest; + if (index + longest > input.length()) { + max = input.length() - index; + } + // implement greedy algorithm by trying maximum match first + for (int i = max; i >= shortest; i--) { + final CharSequence subSeq = input.subSequence(index, index + i); + final String result = lookupMap.get(subSeq.toString()); + + if (result != null) { + out.write(result); + return i; + } + } + } + return 0; + } +} diff --git a/src/org/apache/commons/lang3/text/translate/NumericEntityEscaper.java b/src/org/apache/commons/lang3/text/translate/NumericEntityEscaper.java new file mode 100644 index 0000000..83f6604 --- /dev/null +++ b/src/org/apache/commons/lang3/text/translate/NumericEntityEscaper.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.Writer; + +/** + * Translates codepoints to their XML numeric entity escaped value. + * + * @since 3.0 + * @deprecated as of 3.6, use commons-text + * + * NumericEntityEscaper instead + */ +@Deprecated +public class NumericEntityEscaper extends CodePointTranslator { + + private final int below; + private final int above; + private final boolean between; + + /** + *

              Constructs a NumericEntityEscaper for the specified range. This is + * the underlying method for the other constructors/builders. The below + * and above boundaries are inclusive when between is + * true and exclusive when it is false.

              + * + * @param below int value representing the lowest codepoint boundary + * @param above int value representing the highest codepoint boundary + * @param between whether to escape between the boundaries or outside them + */ + private NumericEntityEscaper(final int below, final int above, final boolean between) { + this.below = below; + this.above = above; + this.between = between; + } + + /** + *

              Constructs a NumericEntityEscaper for all characters.

              + */ + public NumericEntityEscaper() { + this(0, Integer.MAX_VALUE, true); + } + + /** + *

              Constructs a NumericEntityEscaper below the specified value (exclusive).

              + * + * @param codepoint below which to escape + * @return the newly created {@code NumericEntityEscaper} instance + */ + public static NumericEntityEscaper below(final int codepoint) { + return outsideOf(codepoint, Integer.MAX_VALUE); + } + + /** + *

              Constructs a NumericEntityEscaper above the specified value (exclusive).

              + * + * @param codepoint above which to escape + * @return the newly created {@code NumericEntityEscaper} instance + */ + public static NumericEntityEscaper above(final int codepoint) { + return outsideOf(0, codepoint); + } + + /** + *

              Constructs a NumericEntityEscaper between the specified values (inclusive).

              + * + * @param codepointLow above which to escape + * @param codepointHigh below which to escape + * @return the newly created {@code NumericEntityEscaper} instance + */ + public static NumericEntityEscaper between(final int codepointLow, final int codepointHigh) { + return new NumericEntityEscaper(codepointLow, codepointHigh, true); + } + + /** + *

              Constructs a NumericEntityEscaper outside of the specified values (exclusive).

              + * + * @param codepointLow below which to escape + * @param codepointHigh above which to escape + * @return the newly created {@code NumericEntityEscaper} instance + */ + public static NumericEntityEscaper outsideOf(final int codepointLow, final int codepointHigh) { + return new NumericEntityEscaper(codepointLow, codepointHigh, false); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean translate(final int codepoint, final Writer out) throws IOException { + if(between) { + if (codepoint < below || codepoint > above) { + return false; + } + } else { + if (codepoint >= below && codepoint <= above) { + return false; + } + } + + out.write("&#"); + out.write(Integer.toString(codepoint, 10)); + out.write(';'); + return true; + } +} diff --git a/src/org/apache/commons/lang3/text/translate/NumericEntityUnescaper.java b/src/org/apache/commons/lang3/text/translate/NumericEntityUnescaper.java new file mode 100644 index 0000000..bfb5f85 --- /dev/null +++ b/src/org/apache/commons/lang3/text/translate/NumericEntityUnescaper.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.Writer; +import java.util.Arrays; +import java.util.EnumSet; + +/** + * Translate XML numeric entities of the form &#[xX]?\d+;? to + * the specific codepoint. + * + * Note that the semi-colon is optional. + * + * @since 3.0 + * @deprecated as of 3.6, use commons-text + * + * NumericEntityUnescaper instead + */ +@Deprecated +public class NumericEntityUnescaper extends CharSequenceTranslator { + + public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon } + + // TODO?: Create an OptionsSet class to hide some of the conditional logic below + private final EnumSet